Skip to content
Snippets Groups Projects
app.Rmd 33.9 KiB
Newer Older
---
output: html_document
Todor Kondic's avatar
Todor Kondic committed
runtime: shiny_prerendered
author: Environmental Cheminformatics Group, LCSB, University of Luxembourg
Todor Kondic's avatar
Todor Kondic committed
title: "`r paste('Shinyscreen', packageVersion('shinyscreen'))`"
```{r, context='setup', include='false'}
Todor Kondic's avatar
Todor Kondic committed
library(data.table)
library(shinyscreen)
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("il irrilevante",levels=c("il irrilevante",
                                                                                  "il buono",
                                                                                  "il cattivo")))
Todor Kondic's avatar
Todor Kondic committed
## RMassBank masks shiny::validate. Unmask it.
validate <- shiny::validate
## def_state$input$tab$tags <- def_datatab
rv_state <- list2rev(def_state)
compl_sets <- eventReactive(rv_state$input$tab$setid,
                            rv_state$input$tab$setid[,unique(set)])
## Reactive values to support some of the UI elements.
## rv_ui <- reactiveValues(datatab=def_tags)
Todor Kondic's avatar
Todor Kondic committed
## Update with data-files.
rv_dfiles <- reactiveVal(def_datafiles)

## Data-file table when loading.
rv_datatab <- reactiveVal(def_datatab)



# Configuration {.tabset}

## Inputs


<details>
<summary>Specify the project directory</summary>
This is where the output files and the state of the analysis will be
saved.
</details>
```{r, echo=FALSE}
actionButton(inputId = "project_b",
             label= "Project")

```

Current project directory is `r textOutput("project", inline=T)`

<details><summary>Load the compound list(s)</summary>
A compound list is composed of entries describing compounds. This
description is used to search for its spectrum in the data file. The
list is a table in the ***CSV*** format and contains these columns,

* ***ID*** : required column, must be filled; this is a user-defined
  ID, uniquely associated with a compound
  
* ***Name*** : this column can be left blank; if not, it should contain the
  names of the compounds
  
* ***SMILES*** : a _SMILES_ string, describing the structure of the
  compound; this entry can be left empty only if one of either
  ***Formula***, or ***mz*** entries are not
  
* ***Formula*** : a chemical formula of a compound; this field can be
  empty only if one of either ***SMILES***, or ***mz*** entries are
  not
  
* ***mz*** : mass of the ionised compound; this field can be left
  empty only if one of either ***SMILES***, or ***Formula*** is not
  
* ***CAS*** : the CAS number of the compound; it can be left empty

* ***RT*** : retention time of the MS1 peak in minutes, if known; can
  be left empty.
  
Only ***ID*** and one of ***SMILES***, ***Formula*** or ***mz*** must
be filled. When structure, or a formula of a compound is known, it is
also possible to look for various adducts in the sample. Of course,
scanning for completely unknown compounds is also supported by the
***mz*** column. In this case, ***mz*** is the mass of the ion.

It is strongly recommended to quote SMILES, names and formulas in the
CSV file used with Shinyscreen.
</details>
```{r, echo=FALSE}
actionButton(inputId = "comp_list_b",
             label= "Compound list(s)")

```

`r htmlOutput("comp_lists")`

<details><summary>Load compound set list (_setid_ table)</summary>
The compound lists can contain more entries than is necessary. Using
the _setid_ lists, it is possible to create _compound sets_ which
contain only those compounds that will actually be searched for in the
data files. A _setid table_ is a _CSV_ containing at least two
columns,

* ***ID*** : the ID entry from the compound list

* ***set*** : an user-defined set name.
</details>
```{r, echo=FALSE}
actionButton(inputId = "setid_b",
             label= "Load the setid table")

```

`r htmlOutput("setids", inline=T)`

## Data files
<details><summary>Load data files</summary>
Shinyscreen currently supports only the **mzML** file format. After
loading the files, set file tags in the file table (column
**tag**). Additionally, specify a set of compounds that is supposed
to be extracted from the file using the **set** column. Finally,
specify the **adduct** in the adduct column. In case of compounds
with unknown structure and formula, the adduct is ignored for obvious
reasons.
</details>
```{r, echo=FALSE}
actionButton(inputId = "datafiles_b",
             label= "Load data files.")

```




<details><summary>Assign tags to data files.</summary>
Each tag designates an unique file. Use the table below to assign
tags.
</details>

```{r, echo=FALSE}
rhandsontable::rHandsontableOutput("datafiles")

```




<details><summary>Assign sets to tags.</summary>
For each tag, assign a set and an adduct (if the structure information
exists, otherwise _adduct_ column is ignored).
</details>

```{r, echo=F}
rhandsontable::rHandsontableOutput("datatab")
```

## Extraction

### Spectra extraction based settings

Todor Kondic's avatar
Todor Kondic committed
<details><summary>MS1 coarse error</summary>

Extract all entries matching the target mass within this error in the
precursor table.
</details>
```{r, echo=F}
shinyscreen::mz_input(input_mz = "ms1_coarse",
Todor Kondic's avatar
Todor Kondic committed
                       input_unit = "ms1_coarse_unit",
                       def_mz = def_state$conf$tolerance[["ms1 coarse"]],
                       def_unit = "Da")
Todor Kondic's avatar
Todor Kondic committed
<details><summary>MS1 fine error</summary>

The precursor table masses can be of lower accuracy. Once there is a
match within the coarse error, it can be further checked versus the
fine error bounds directly in the mass spectrum.

</details>
```{r, echo=F}
shinyscreen::mz_input(input_mz = "ms1_fine",
                      input_unit = "ms1_fine_unit",
                      def_mz = def_state$conf$tolerance[["ms1 fine"]],
                      def_unit = "ppm")
```

Todor Kondic's avatar
Todor Kondic committed
<details><summary>MS1 EIC window</summary>

The mz interval over which the intensities are aggregated to generate
a chromatogram.

</details>
```{r, echo=F}
shinyscreen::mz_input(input_mz = "ms1_eic",
                      input_unit = "ms1_eic_unit",
                      def_mz = def_state$conf$tolerance[["eic"]],
                      def_unit = "Da")
```

Todor Kondic's avatar
Todor Kondic committed
<details><summary>Retention time window</summary>

If the expected retention time has been specified for the compound,
then search for the MS1 signature inside the window defined by this
range.

</details>
```{r, echo=F}
shinyscreen::rt_input(input_rt = "ms1_rt_win",
                      input_unit = "ms1_rt_win_unit",
                      def_rt = def_state$conf$tolerance[["rt"]],
                      def_unit = "min")
```

## Prescreening

Todor Kondic's avatar
Todor Kondic committed
<details><summary>MS1 intensity threshold</summary>

Ignore MS1 signal below the threshold.

</details>
```{r, echo=F}

numericInput(inputId = "ms1_int_thresh",
             label = NULL,
             value = def_state$conf$prescreen$ms1_int_thresh)
```

Todor Kondic's avatar
Todor Kondic committed
<details><summary>MS2 intensity threshold</summary>

Ignore MS2 signal below the threshold.

</details>
```{r, echo=F}

numericInput(inputId = "ms2_int_thresh",
             label = NULL,
             value = def_state$conf$prescreen$ms2_int_thresh)
```


MS1 signal-to-noise ratio.

```{r, echo=F}

numericInput(inputId = "s2n",
             label = NULL,
             value = def_state$conf$prescreen$s2n)
```


Todor Kondic's avatar
Todor Kondic committed
<details><summary>MS1/MS2 retention delay.</summary>

Look for associated MS2 spectrum within this window around the MS1
peak.

</details>
```{r, echo=F}
shinyscreen::rt_input(input_rt = "ret_time_shift_tol",
                      input_unit = "ret_time_shift_tol_unit",
Todor Kondic's avatar
Todor Kondic committed
                      def_rt = def_state$conf$prescreen[["ret_time_shift_tol"]],
                      def_unit = "min")
```

Todor Kondic's avatar
Todor Kondic committed
## Filter and order the summary table
<div style= "display: flex; vertical-align:top; ">
Todor Kondic's avatar
Todor Kondic committed

<div style="padding-right: 0.5em">
Todor Kondic's avatar
Todor Kondic committed
<details><summary>Filter summary table</summary>
Todor Kondic's avatar
Todor Kondic committed

Filter entries in the summary table according to the QA criteria.
Todor Kondic's avatar
Todor Kondic committed

* **qa_pass** : entries that passed all checks

* **qa_ms1_exists** : MS1 intensity is above the MS1 threshold

* **qa_ms2_exists** : those entries for which some MS2 spectra have been found

* **qa_ms1_above_noise** : MS1 is intense enough and above the noise level

* **qa_ms2_good_int** : MS2 intensity is above the MS2 threshold

* **qa_ms2_near** : MS2 spectrum is close enough to the MS1 peak
Todor Kondic's avatar
Todor Kondic committed

For those who do not speak Italian (and do not dig the bad Sergio
Leone pun):

* **l'irrelevante** : ignore QA criterion
Todor Kondic's avatar
Todor Kondic committed
* **il buono** : entry passed QA
* **il cattivo** : entry failed QA

Todor Kondic's avatar
Todor Kondic committed
</details>
```{r, echo=F}
Todor Kondic's avatar
Todor Kondic committed

rhandsontable::rHandsontableOutput("summ_subset")

Todor Kondic's avatar
Todor Kondic committed
```
</div>
Todor Kondic's avatar
Todor Kondic committed

<div style="padding-left: 0.5em">

Todor Kondic's avatar
Todor Kondic committed
<details><summary>Ordering by columns</summary>
It is possible to order the summary table using columns (keys): 
*`r paste(gsub("^-(.+)","\\1",shinyscreen:::DEF_INDEX_SUMM), collapse = ',')`*.
The sequence of columns in the table below describes the
sequence of ordering steps -- the key in the first row sorts the
entire summary table and subsequent keys break the ties.

</details>

```{r, echo=F}
rhandsontable::rHandsontableOutput("order_summ")
```

</div>

</div>

### Logarithmic axis

```{r, echo=F}
checkboxGroupInput("plot_log",
                   label=NULL,
Todor Kondic's avatar
Todor Kondic committed
                   choices = c("MS1 EIC","MS2 EIC","MS2 Spectrum"),
                   selected = character(0))
```

### Global retention time range
```{r, echo=F}
shinyscreen::rt_input(input_rt = "plot_rt_min",
                      input_unit = "plot_rt_min_unit",
                      def_rt = NA_real_,
                      def_unit = "min",
                      pref = "min:")

shinyscreen::rt_input(input_rt = "plot_rt_max",
                      input_unit = "plot_rt_max_unit",
                      def_rt = NA_real_,
                      def_unit = "min",
                      pref = "max:")
```

### Grouping plots

<details><summary>How to group plots?</summary> 

The _Select plot group_ and _Select plot label_ controls control how
the data is visually grouped together. The _plot group_ groups
together multiple curves in a single graph. Each curve in a graph is
designated by the _plot label_.

</details>

<div style= "display: flex; vertical-align:top; ">

<div style="padding-right:0.5em;">
```{r, echo=F}
p_feats <- 1:length(shinyscreen:::PLOT_FEATURES)
names(p_feats) <- shinyscreen:::PLOT_FEATURES
selectInput(inputId = "plot_grp_plot",
            label = "Select plot group",
            choices = p_feats,
            selected = p_feats[[shinyscreen:::FIG_DEF_CONF$grouping[["plot"]]]],
            width  = "100%")
```
</div>

<div style="padding-left:0.5em;">
```{r, echo=F}
p_feats <- 1:length(shinyscreen:::PLOT_FEATURES)
names(p_feats) <- shinyscreen:::PLOT_FEATURES
selectInput(inputId = "plot_label",
            label = "Select plot label",
            choices = p_feats,
            selected = p_feats[[shinyscreen:::FIG_DEF_CONF$grouping[["label"]]]],
            width = "100%")
```
</div>

</div>
```{r, echo=F}
shiny::textInput(inputId = "rep_aut", label = "Report author", value = def_state$conf$report$author)
shiny::textInput(inputId = "rep_tit", label = "Report title", value = def_state$conf$report$title)
```

# View compound Lists and Sets {.tabset}

## Compound List

```{r, echo=F}
DT::dataTableOutput("comp_table")
```

## Setid Table
```{r, echo=F}
DT::dataTableOutput("setid_table")
```

# Save and Restore
Shinyscreen can start from either a previously saved _state_ file (in
RDS format), or from a _YAML_ config file. States saved using GUI can
also be used from the script.
Todor Kondic's avatar
Todor Kondic committed

```{r, echo=FALSE}
actionButton(inputId = "state_file_load_b",
             label= "Restore project state")
Todor Kondic's avatar
Todor Kondic committed

```{r, echo=FALSE}
actionButton(inputId = "state_file_save_b",
             label= "Save project state")
# Extract Data and Prescreen
<details><summary>Extract spectra from data files.</summary>

After Shinyscreen is configured, the compound and setid lists loaded, it
is possible to proceed with extracting the data. This is potentially a
time-intensive step, so some patience might be needed.

Once the data is extracted, it will be possible to quality check the
spectra associated with the compounds specified in the _setid_ list,
to subset that data, look at the plots and publish a report.

</details>
```{r, echo=FALSE}
Todor Kondic's avatar
Todor Kondic committed
actionButton(inputId = "extract_b",
             label = "Extract")
```

<details><summary>Prescreen extracted spectra.</summary>

After the data extraction is finished, the quality of the retrieved
spectra can be checked using the criteria defined in the
_Prescreening_ tab of the _Configuration_ Section. The resulting
_summary table_ is given below and is based on the prescreening
criteria and filter and ordering setup specified in _Filter and order
the summary table_ configuration subsection.

</details>

</details>
```{r, echo=FALSE}
actionButton(inputId = "presc_b",
             label = "Prescreen and filter")
```

```{r, echo=FALSE}
DT::dataTableOutput("summ_table")
```


# Browse Results
Todor Kondic's avatar
Todor Kondic committed

Generate plots.

```{r, echo=F}

uiOutput("plot_b_ctrl")

```
<div style="display: flex; ">

<div>
```{r, echo=F}

uiOutput("plot_set_b_ctrl")

## selectInput(inputId = "plot_set_b",
##             label = "Select set",
##             choices = c("uninitialised"=0))
```
</div>

<div style="vertical-align: bottom; ">
```{r, echo=F}

uiOutput("plot_id_b_ctrl")
## selectInput(inputId = "plot_id_b",
##             label = "Select ID",
##             choices = c("uninitialised"=0))
```
</div>

</div>


<div style="display: flex; ">

<div style="vertical-align: bottom; ">
```{r, echo=F}
actionButton(inputId = "plot_next_b",
             label = "Previous")
```
</div>

<div style="vertical-align: bottom; ">
```{r, echo=F}
actionButton(inputId = "plot_prev_b",
             label = "Next")
```
</div>


</div>
Todor Kondic's avatar
Todor Kondic committed

<!-- ENGINE -->

<!-- setup is here  -->
Todor Kondic's avatar
Todor Kondic committed

```{r, include="false", context='setup'}
Todor Kondic's avatar
Todor Kondic committed
ord_nms <- gsub("^-(.+)","\\1",shinyscreen:::DEF_INDEX_SUMM)
ord_asc <- grepl("^-.+",shinyscreen:::DEF_INDEX_SUMM)
ord_asc <- factor(ifelse(ord_asc, "descending", "ascending"),levels = c("ascending","descending"))
Todor Kondic's avatar
Todor Kondic committed
def_ord_summ <- shinyscreen:::dtable("Column Name"=ord_nms,"Direction"=ord_asc)
update_gui <- function(in_conf, session) {
    upd_unit <- function(entry,inp_val,inp_unit,choices) {
        if (isTruthy(entry)) {
            cntnt <- strsplit(entry,split = "[[:space:]]+")[[1]]
            cntnt <- cntnt[nchar(cntnt) > 0]
            if (length(cntnt)!=2) stop("(upd_unit) ","Unable to interpret ", entry)
            val <- cntnt[[1]]
            unit <- cntnt[[2]]
            updateNumericInput(session = session,
                               inputId = inp_val,
                               value = as.numeric(val))
            updateSelectInput(session = session,
                              inputId = inp_unit,
                              selected = unit,
                              choices = choices)
        }
    }

    upd_num <- function(entry,inp_val) {
        if (isTruthy(entry)) {
            updateNumericInput(session = session,
                               inputId = inp_val,
                               value = as.numeric(entry))
        }
    }

    upd_sel <- function(inputId,selected,choices) {
        if (isTruthy(selected)) {
            updateSelectInput(session = session,
                              inputId = inputId,
                              selected = selected,
                              choices = choices)
        }
    }

    isolate({
        rv_state$conf$project <- in_conf$project
        rv_state$conf$data <- in_conf$data
        ## Lists
        rv_state$conf$compounds$lists <- in_conf$compounds$lists
        rv_state$conf$compounds$sets <- in_conf$compounds$sets
        
        ## Tolerance
        
        upd_unit(in_conf$tolerance[["ms1 fine"]],
                 "ms1_fine",
                 "ms1_fine_unit",
                 choices=c("ppm","Da"))
        upd_unit(in_conf$tolerance[["ms1 coarse"]],
                 "ms1_coarse",
                 "ms1_coarse_unit",
                 choices=c("ppm","Da"))

        upd_unit(in_conf$tolerance[["eic"]],
                 "ms1_eic",
                 "ms1_eic_unit",
                 choices=c("ppm","Da"))
        upd_unit(in_conf$tolerance[["rt"]],
                 "ms1_rt_win",
                 "ms1_rt_win_unit",
                 choices=c("min","s"))

        ## Prescreen
        upd_num(in_conf$prescreen[["ms1_int_thresh"]],
                "ms1_int_thresh")
        upd_num(in_conf$prescreen[["ms2_int_thresh"]],
                "ms2_int_thresh")
        upd_num(in_conf$prescreen[["s2n"]],
                "s2n")
        upd_unit(in_conf$prescreen[["ret_time_shift_tol"]],
                 "ret_time_shift_tol",
                 "ret_time_shift_tol_unit",
                 choices=c("min","s"))

        ## Files
        df <- shinyscreen:::file2tab(in_conf$data)
        df[,tag:=as.character(tag),with=T]
        rv_dfiles(df[,.(File=Files,tag),by=c("Files","tag"),mult="first"])
        nms <- colnames(df)
        nms <- nms[nms!="Files"]
        fdt <- df[,..nms]
        rv_datatab(fdt)

        ## figures
        upd_unit(in_conf$figures$rt_min,
                 "plot_rt_min",
                 "plot_rt_min_unit",
                 choices=c("min","s"))
        
        upd_unit(in_conf$figures$rt_max,
                 "plot_rt_max",
                 "plot_rt_max_unit",
                 choices=c("min","s"))

        logentry <- in_conf$figures$logaxes
        logchoice <- logical(0)
        logchoice <- mapply(function(cn,uin) if (cn %in% logentry) uin else NA,
                            c("ms1_eic_int","ms2_eic_int","ms2_spec_int"),
                            c("MS1 EIC","MS2 EIC","MS2 Spectrum"),USE.NAMES = F)
        logchoice <- logchoice[!is.na(logchoice)]
        
        updateCheckboxGroupInput(session = session,
                                 inputId = "plot_log",
                                 choices = c("MS1 EIC",
                                             "MS2 EIC",
                                             "MS2 Spectrum"),
                                 selected = logchoice)
        ## Report
        if (isTruthy(in_conf$report$author)) updateTextInput(session,"rep_aut",value = in_conf$report$author)
        if (isTruthy(in_conf$report$title)) updateTextInput(session,"rep_tit",value = in_conf$report$title)

        
    })
}

```{r, include="false", context='server'}
## reactive functions

Todor Kondic's avatar
Todor Kondic committed
observeEvent(input$setid_b, {
    filters <- matrix(c("CSV files", ".csv",
                        "All files", "*"),
Todor Kondic's avatar
Todor Kondic committed
                      2, 2, byrow = TRUE)
Todor Kondic's avatar
Todor Kondic committed
    setids <- tcltk::tk_choose.files(filters=filters)
    message("(config) Selected compound sets (setid): ", paste(setids,collapse = ","))
    rv_state$conf$compounds$sets <- if (length(setids)>0 && nchar(setids[[1]])>0) setids else "Nothing selected."
})



rf_compound_input_state <- reactive({
    sets <- rv_state$conf$compounds$sets
    lst <- as.list(rv_state$conf$compounds$lists)
    validate(need(length(lst)>0,
                  message = "Load the compound lists(s) first."))
Todor Kondic's avatar
Todor Kondic committed
    validate(need(length(sets)>0 && nchar(sets)>0,
                  message = "Load the setid table first."))
    isolate({
        state <- rev2list(rv_state)
        m <- load_compound_input(state)
        ## Side effect! This is because my pipeline logic does not
        ## work nicely with reactive stuff.
        rv_state$input$tab$cmpds <- list2rev(m$input$tab$cmpds)
        rv_state$input$tab$setid <- m$input$tab$setid
        m
Todor Kondic's avatar
Todor Kondic committed
    })
Todor Kondic's avatar
Todor Kondic committed

rf_conf_proj <- reactive({
Todor Kondic's avatar
Todor Kondic committed
    
Todor Kondic's avatar
Todor Kondic committed
    state <- rev2list(rv_state)
    dir.create(state$conf$project,showWarnings = F)
    state
    
})

rf_conf_state <- reactive({
    state <- rf_conf_proj()
    ## mzml1 <- rf_get_inp_datatab()
    ## mzml1[,`:=`(tag=as.character(tag),
    ##             set=as.character(set),
    ##             adduct=as.character(adduct))]
    ## mzml2 <- rf_get_inp_datafiles()
    
    ## mzml <- mzml1[mzml2,on="tag"]
Todor Kondic's avatar
Todor Kondic committed
    
Todor Kondic's avatar
Todor Kondic committed
    ftab <- get_fn_ftab(state)
    state$conf$data <- ftab
    state$conf[["summary table"]]$filter <- rf_get_subset()
    state$conf[["summary table"]]$order <- rf_get_order()
    state
})

rf_get_subset <- reactive({
    dt <- tryCatch(rhandsontable::hot_to_r(input$summ_subset),
                   error = function(e) def_summ_subset)
    dt[Select == "il buono", extra := T]
    dt[Select == "il cattivo", extra := F]
    sdt <- dt[!is.na(extra)]
    if (NROW(sdt) > 0) {
        sdt[,paste0(`QA Column`," == ",extra)]
    } else NULL
})

rf_get_order <- reactive({
    dt <- tryCatch(rhandsontable::hot_to_r(input$order_summ),error = function(e) def_ord_summ)
    tmp <- dt[Direction == "descending",.(`Column Name`=paste0("-",`Column Name`))]
    tmp[,`Column Name`]
Todor Kondic's avatar
Todor Kondic committed

rf_get_inp_datatab <- eventReactive(input$datatab,{
    z <- data.table::as.data.table(tryCatch(rhandsontable::hot_to_r(input$datatab)),
                                   error = function(e) def_datatab)

Todor Kondic's avatar
Todor Kondic committed
    z[,.(tag=as.character(tag),
         adduct=as.character(adduct),
         set=as.character(set)), with = T]
})

rf_get_inp_datafiles <- eventReactive(input$datafiles,{
    z <- data.table::as.data.table(tryCatch(rhandsontable::hot_to_r(input$datafiles)),
                                   error = function(e) def_datafiles)

    
    z[,.(File,
         tag=as.character(tag)), with = T]
})
Todor Kondic's avatar
Todor Kondic committed
```
Todor Kondic's avatar
Todor Kondic committed
```{r, include="false", context='server'}

observeEvent(input$project_b,{
    wd <- tcltk::tk_choose.dir(default = getwd(),
                               caption = "Choose project directory")
    message("Set project dir to ", wd)
    rv_state$conf$project <- wd
})

observeEvent(input$comp_list_b, {
    filters <- matrix(c("CSV files", ".csv",
                        "All files", "*"),
Todor Kondic's avatar
Todor Kondic committed
                      2, 2, byrow = TRUE)
    compfiles <- tcltk::tk_choose.files(filters=filters)
    message("(config) Selected compound lists: ", paste(compfiles,collapse = ","))
    rv_state$conf$compounds$lists <- if (length(compfiles)>0 && nchar(compfiles[[1]])>0) compfiles else "Nothing selected."
})

Todor Kondic's avatar
Todor Kondic committed
observeEvent(input$datafiles_b,{
    filters <- matrix(c("mzML files", ".mzML",
                        "All files", "*"),
                      2, 2, byrow = TRUE)
    fns <- tcltk::tk_choose.files(filters=filters)
    message("(config) Selected data files: ", paste(fns,collapse = ","))
    ## Did the user choose any files?
    if (length(fns) > 0) {
        oldtab <- rf_get_inp_datafiles()
Todor Kondic's avatar
Todor Kondic committed
        
        newf <- setdiff(fns,oldtab$File)
        nr <- NROW(oldtab)
        tmp <- if (length(newf)>0) shinyscreen:::dtable(File=newf,tag=paste0('F',(nr+1):(nr + length(newf)))) else shinyscreen:::dtable(File=character(),tag=character())

        z <- rbind(oldtab, tmp)
        z[,tag:=as.character(tag)]
        rv_dfiles(z)
    }
})

observe({
    df_tab <- rf_get_inp_datafiles()
Todor Kondic's avatar
Todor Kondic committed
    state <- rf_compound_input_state()
    isolate(oldtab <- rf_get_inp_datatab())
Todor Kondic's avatar
Todor Kondic committed
    oldt <- oldtab$tag
    tagl <- df_tab$tag
    diff <- setdiff(tagl,
                    oldt)
    
    res <- if (length(diff)!=0) {
               ## Only change the tag names in the old ones.
               pos_tag <- 1:length(tagl)
               pos_old <- 1:NROW(oldtab)
               pos_mod <- intersect(pos_tag,pos_old)
               new_tag <- tagl[pos_mod]
               if (NROW(oldtab)>0) oldtab[pos_mod,tag := ..new_tag]

               ## Now add tags for completely new files, if any.
               rest_new <- if (NROW(oldtab) > 0) setdiff(diff,new_tag) else diff
               tmp <- shinyscreen:::dtable(tag=rest_new,
                                           adduct=character(0),
                                           set=character(0))

               dt <-data.table::as.data.table(rbind(as.data.frame(oldtab),
                                                    as.data.frame(tmp)))
               dt[tag %in% df_tab$tag,]
           } else oldtab
    
    rv_datatab(res)
})

observe({
    dtab <- rv_datatab()
    dfiles <- rv_dfiles()
    message("(config) Generating mzml from rv.")
    isolate(rv_state$input$tab$mzml <- dtab[dfiles,on="tag"])
Todor Kondic's avatar
Todor Kondic committed

    
}, label = "mzml_from_rv")

observe({
    dtab <- rf_get_inp_datatab()
    dfiles <- rf_get_inp_datafiles()

    message("(config) Generating mzml from inputs.")
    res <- dtab[dfiles,on="tag"]
    data.table::setnames(res,"File","Files")
    isolate(rv_state$input$tab$mzml <- res)

    
}, label = "mzml_from_inp")
Todor Kondic's avatar
Todor Kondic committed

observeEvent(input$extract_b,{
    m <- rf_conf_state()
    fn_c_state <- file.path(m$conf$project,
Todor Kondic's avatar
Todor Kondic committed
                            paste0("extract.",shinyscreen:::FN_CONF))
    yaml::write_yaml(x=m$conf,file=fn_c_state)
    message("(extract) Config written to ", fn_c_state)
    state <- withr::with_dir(new=m$conf$project,
Todor Kondic's avatar
Todor Kondic committed
                             code = {
                                 m <- setup_phase(m)
                                 m <- mk_comp_tab(m)
                                 extr_data(m)
Todor Kondic's avatar
Todor Kondic committed
                             })
    message("(extract) Done extracting.")
    z <- shinyscreen::merge2rev(rv_state,lst = state)
    eval(z)
    ## rv_state <<- list2rev(state)
    
})

observeEvent(input$presc_b,{
    validate(need(NROW(rv_state$extr$ms) > 0,
                  message = "Perform extraction first."))
    m <- rev2list(rv_state)

    fn_c_state <- file.path(m$conf$project,
                            paste0("presc.",shinyscreen:::FN_CONF))
    yaml::write_yaml(x=m$conf,file=fn_c_state)
    message("(prescreen) Config written to ", fn_c_state)
    state <- withr::with_dir(new=m$conf$project,
                             code = {
                                 m <- prescreen(m)
                                 m <- sort_spectra(m)
                                 subset_summary(m)
                             })
    message("(prescreen) Done prescreening.")
    
    z <- shinyscreen::merge2rev(rv_state,lst = state)
    eval(z)
    
Todor Kondic's avatar
Todor Kondic committed
    
observeEvent(input$plot_b,{
    validate(need(NROW(rv_state$out$tab$flt_summ) > 0,
                  message = "Perform prescreening first."))
    m <- rev2list(rv_state)

    fn_c_state <- file.path(m$conf$project,
                            paste0("genplot.",shinyscreen:::FN_CONF))
    yaml::write_yaml(x=m$conf,file=fn_c_state)
    message("(generate plots) Config written to ", fn_c_state)
    state <- withr::with_dir(new=m$conf$project,
                             code = {
                                 m <- create_plots(m)
                                 save_plots(m)
                             })
    message("(generate plots) Done generating plots.")
    
    z <- shinyscreen::merge2rev(rv_state,lst = state)
    eval(z)
})

observeEvent(input$state_file_load_b,{
    filters <- matrix(c("RDS files", ".rds",
                        "YAML config files", ".yaml",
    fn <- tcltk::tk_choose.files(filters=filters,
                                 multi = F)
    
    message("(config) Loading state from: ", paste(fn,collapse = ","))
    fn <- if (length(fn)>0 && nchar(fn[[1]])>0) fn else ""
        if (grepl("yaml",fn)) {
            state <- new_state_fn_conf(fn)
            conf <- state$conf
            update_gui(conf,session=session)
        } else {
            state <- readRDS(file=fn)
            z <- shinyscreen::merge2rev(rv_state,lst = state)
            eval(z)
            update_gui(rv_state$conf, session=session)
        }
observeEvent(input$state_file_save_b,{
    filters <- matrix(c("RDS files", ".rds",
                        "All files", "*"),
                      2, 2, byrow = TRUE)
    fn <- tk_save_file(filters=filters,                       
                       default = "state.rds")
    message("(config) Saving state to: ", paste(fn,collapse = ","))
    fn <- if (length(fn)>0 && nchar(fn[[1]])>0) fn else ""

    if (nchar(fn) > 0) {
        m <- rev2list(rv_state)
        ftab <- get_fn_ftab(m)
        fconf <- get_fn_conf(m)
        yaml::write_yaml(m$conf,
                         file = fconf)
        shinyscreen:::tab2file(tab=m$input$tab$mzml,file=ftab)
        m$conf$data <- ftab
Todor Kondic's avatar
Todor Kondic committed
```

<!-- Tolerance -->
```{r, include='false', context = 'server'}
uni_ass <- function(val,unit) {
    paste(input[[val]],
          input[[unit]])
}
observe({
    
    rv_state$conf$tolerance[["ms1 fine"]] <- uni_ass("ms1_fine",
                                                     "ms1_fine_unit")
    
    rv_state$conf$tolerance[["ms1 coarse"]] <- uni_ass("ms1_coarse",
                                                       "ms1_coarse_unit")

    rv_state$conf$tolerance[["eic"]] <- uni_ass("ms1_eic",
                                                "ms1_eic_unit")

    rv_state$conf$tolerance[["rt"]] <- uni_ass("ms1_rt_win",
                                               "ms1_rt_win_unit")


})
```

<!-- Prescreen -->
```{r, include='false', context = 'server'}
## uni_ass <- function(val,unit) {
##     paste(input[[val]],
##           input[[unit]])
## }
observe({
    
    rv_state$conf$prescreen[["ms1_int_thresh"]] <- input[["ms1_int_thresh"]]
    rv_state$conf$prescreen[["ms2_int_thresh"]] <- input[["ms2_int_thresh"]]
    rv_state$conf$prescreen[["s2n"]] <- input$s2n
    rv_state$conf$prescreen[["ret_time_shift_tol"]] <- uni_ass("ret_time_shift_tol",
                                                               "ret_time_shift_tol_unit")

})
Todor Kondic's avatar
Todor Kondic committed
<!-- Plotting -->
```{r, include='false', context = 'server'}
observe({
    vals <- input$plot_log
    checked <- c("MS1 EIC"=F,
                 "MS2 EIC"=F,
                 "MS2 Spectrum"=F)
    if (length(vals)!=0) checked[vals] <- T
    l <- list()
    l <- c(if (checked[["MS1 EIC"]]) "ms1_eic_int" else NULL,l)
    l <- c(if (checked[["MS2 EIC"]]) "ms2_eic_int" else NULL,l)
    l <- c(if (checked[["MS2 Spectrum"]]) "ms2_spec_int" else NULL,l)
    rv_state$conf$figures[["logaxes"]] <- l[!sapply(l,is.null)]
	
	rv_state$conf$figures$rt_min <- uni_ass("plot_rt_min","plot_rt_min_unit")
	rv_state$conf$figures$rt_max <- uni_ass("plot_rt_max","plot_rt_max_unit")
})
```
<!-- Report -->
```{r, include='false', context = 'server'}
observe({
	rv_state$conf$report$author <- input$rep_aut
	rv_state$conf$report$title <- input$rep_tit
})
```

<!-- Render -->
```{r, include="false", context="server"}
output$project <- renderText(rv_state$conf$project)

output$comp_lists <- renderText({
    lsts <- rev2list(rv_state$conf$compounds$lists)
    if (length(lsts) > 0 &&
        isTruthy(lsts) &&
        lsts != "Nothing selected.") {
        paste(c("<ul>",
                sapply(lsts,
                       function (x) paste("<li>",x,"</li>")),
                "</ul>"))
    } else "No compound list selected yet."
})

output$setids <- renderText({
    sets <- rv_state$conf$compounds$sets
    if (isTruthy(sets) && sets != "Nothing selected.")
        paste("selected <em>setid</em> table:",
              sets) else "No <em>setid</em> table selected."
})

Todor Kondic's avatar
Todor Kondic committed
output$order_summ <- rhandsontable::renderRHandsontable(rhandsontable::rhandsontable(def_ord_summ,
                                                                                     manualRowMove = T))

output$datafiles <- rhandsontable::renderRHandsontable(
{
Todor Kondic's avatar
Todor Kondic committed
    res <- rv_dfiles()
    rhandsontable::rhandsontable(as.data.frame(res),
                                 width = "50%",
                                 height = "25%",
                                 allowInvalid=F)
})

output$datatab <- rhandsontable::renderRHandsontable(
{
Todor Kondic's avatar
Todor Kondic committed
    setid <- rv_state$input$tab$setid
Todor Kondic's avatar
Todor Kondic committed
    res <- rv_datatab()
Todor Kondic's avatar
Todor Kondic committed
    if (NROW(res)>0) {
        res$tag <- factor(res$tag,
                          levels = c(unique(res$tag),
                                              "invalid"))
        res$set <- factor(res$set,
                          levels = c(unique(setid$set),
                                             "invalid"))
        res$adduct <- factor(res$adduct,
                             levels = shinyscreen:::DISP_ADDUCTS)
    }


    rhandsontable::rhandsontable(res,stretchH="all",
                                 allowInvalid=F)
})

output$comp_table <- DT::renderDataTable({
    state <- rf_compound_input_state()


    DT::datatable(state$input$tab$cmpds,
                  style = 'bootstrap',
                  class = 'table-condensed',
                  extensions = 'Scroller',
                  options = list(scrollX = T,
                                 scrollY = 200,
                                 deferRender = T,
                                 scroller = T))
})

output$setid_table <- DT::renderDataTable({
    state <- rf_compound_input_state()

    DT::datatable(state$input$tab$setid,
                  style = 'bootstrap',
                  class = 'table-condensed',
                  extensions = 'Scroller',
                  options = list(scrollX = T,
                                 scrollY = 200,
                                 deferRender = T,
                                 scroller = T))
Todor Kondic's avatar
Todor Kondic committed

output$summ_subset <- rhandsontable::renderRHandsontable({
    

    rhandsontable::rhandsontable(def_summ_subset)
})

output$summ_table <- DT::renderDataTable({

    
    tab <- rv_state$out$tab$flt_summ
    nms <- colnames(tab)
    dpl_nms <- nms[nms!="Files"]
    validate(need(NROW(tab)>0, message = "Please prescreen the data first."))
    DT::datatable(tab[,..dpl_nms],
                  style = 'bootstrap',
                  class = 'table-condensed',
                  extensions = 'Scroller',
                  options = list(scrollX = T,
                                 scrollY = 200,
                                 deferRender = T,
                                 scroller = T))
})
output$plot_set_b_ctrl <- renderUI({
    tab <- rv_state$out$tab$flt_summ
    req(NROW(tab)>0)
    selectInput(inputId = "plot_set_b",
                label = "Select set",
                choices = c("uninitialised"=0))
})

output$plot_b_ctrl <- renderUI({
    tab <- rv_state$out$tab$flt_summ
    req(NROW(tab)>0)
    actionButton(inputId = "plot_b",
             label= "Generate plots")
    
})
```
```{r, echo=F, context = 'server'}
session$onSessionEnded(function () stopApp())
Todor Kondic's avatar
Todor Kondic committed
```