R/app_server.R

Defines functions app_server

#' The application server-side
#' 
#' @param input,output,session Internal parameters for {shiny}. 
#'     DO NOT REMOVE.
#' @import shiny
#' @rawNamespace import(ggplot2, except = last_plot)
#' @rawNamespace import(plotly, except = rename)
#' @importFrom stats prcomp kmeans dist hclust
#' @importFrom shinyFiles shinyDirChoose getVolumes parseDirPath
#' @importFrom fs path_home
#' @importFrom DT renderDT datatable JS
#' @importFrom stringr str_sub str_split_fixed str_replace
#' @importFrom purrr flatten pluck
#' @import shinyBS
#' @importFrom DataEditR dataEditServer dataOutputServer
#' @importFrom lubridate as_date
#' @importFrom VIM aggr
#' @importFrom shinyWidgets sendSweetAlert show_alert
#' @importFrom grDevices colorRampPalette
#' @importFrom RColorBrewer brewer.pal
#' @import ggfortify
#' @importFrom tidyr gather separate pivot_longer unite
#' @importFrom forcats fct_rev
#' @import utils
#' @importFrom tibble rownames_to_column as_tibble column_to_rownames
#' @import ggVennDiagram
#' @importFrom ComplexHeatmap make_comb_mat comb_size comb_degree UpSet upset_right_annotation draw column_order decorate_annotation anno_barplot
#' @importFrom grid gpar unit grid.text
#' @importFrom mixOmics plsda background.predict plotIndiv plotVar perf splsda tune.splsda color.jet color.mixo
#' @importFrom gridExtra grid.arrange
#' @importFrom cluster pam clara
#' @importFrom factoextra fviz_nbclust fviz_cluster eclust fviz_dend fviz_silhouette
#' @importFrom metabolomicsWorkbenchR do_query
#' @importFrom openxlsx write.xlsx read.xlsx
#' @importFrom graphics par
#' @import scales
#' @noRd




app_server <- function( input, output, session ) {
  # Your application server logic 
  
  options(scipen = 999)
  
  observeEvent(input$jumptohome, {
    shinydashboard::updateTabItems(session, "sidebarmenu", "home")
  })
  
  observeEvent(input$gotoimport, {
    shinydashboard::updateTabItems(session, "sidebarmenu", selected = "rawsub")
  })
  
  
  # the modal dialog where the user can enter the query details.
  query_modal <- modalDialog(
    h3(strong("Welcome to ADViSELipidomics"), style = "text-align: center"),
    br(),
    h4("Before start, please enter your name and your company. These informations will be saved in the metadata of your SumExp output."),
    textInput("indata_analyst", list(HTML("&nbsp;"), icon("user"), HTML("&nbsp;Enter your name")), value = "User"),
    textInput("inlab_analyst", list(HTML("&nbsp;"), icon("building"), HTML("&nbsp;Enter your institute")), value = "Institute"),
    easyClose = F,
    footer = tagList(
      actionButton("run", "Run")
    )
  )

  
  
  # # Show the model on start up ...
  # observeEvent(input$sidebarmenu,{
  #   req(input$sidebarmenu == "rawsub")
  #   showModal(query_modal)
  # },ignoreInit = TRUE, once = TRUE)
  

  # ... or when user wants to change query
  observeEvent(input$change,{
    showModal(query_modal)
  })

  observeEvent(input$run, {
    removeModal()
  })
  
  output$nome = renderText({
    if(is.null(input$indata_analyst)){
      "User"
    }else{
      input$indata_analyst
    }
  })


  analysis = reactive({
    list(
      lab_analyst = input$inlab_analyst,
      data_analyst = input$indata_analyst,
      pipe_ver = utils::packageVersion("ADViSELipidomics"),
      analysis_date = date()
    )
  })

  
  
  # this makes the directory at the base of your computer.
  volumes = c(Home = fs::path_home(), shinyFiles::getVolumes()())
  
  
  ######## STEP FILTERING ###########
  
  stepc = mod_reading_step_server("reading_step_lipsearch", analysis = analysis, int_std = reactive(input$type_lipsearch))
  


  ######### STEP CALIBRATION ##########
  
  ###check end of filtering box
  output$checkendfiltering = reactive(
    return(is.null(stepc()))
  )
  outputOptions(output, "checkendfiltering", suspendWhenHidden = FALSE)
  
  
  ####PART 1. import calibration files
  
  stepgwith = mod_calibration_step_server("calibration_step_lipsearch_with", stepc = stepc)
  
  stepg = reactive({
    req(stepc())
    if(input$type_lipsearch == 'No'){
      data_list <- lapply(stepc()$lipid_filtered, function(x) x %>%
                            dplyr::select(LipidIon,Area))
      
      data_updated = list()
      for(k in 1:length(data_list)){
        name = gsub("_nonlabeled","",names(data_list[k]))
        data_updated[k] = list(data_list[[k]] %>% dplyr::rename(!!name := "Area"))
      }
      
      merged = data_updated %>% purrr::reduce(dplyr::full_join, by = "LipidIon") %>% 
        dplyr::rename("Lipids" = "LipidIon")
      
      #return stepg$concentration_matrix with everything else
      list(stepc(), concentration_matrix = list(concentration_matrix = merged)) %>% purrr::flatten()
    }else{
      stepgwith()
    }

  })
  

  
  #check data correctly loaded
  output$checkstepg = reactive(
    return(is.null(stepg()))
  )
  outputOptions(output, "checkstepg", suspendWhenHidden = FALSE)
  
  observeEvent(stepg(),{
    num_na = sum(is.na(stepg()$concentration_matrix))
    not_na = sum(!is.na(stepg()$concentration_matrix))
    
    if (num_na/(num_na+not_na) > 0.5){
      shinyWidgets::sendSweetAlert(session, title = "Too many NAs", type = "warning", width = "600px",
                                   text = tags$div(
                                     p(tags$div("More than 50% of the calibration matrix data are NAs.", style = "font-weight: bold;")),
                                     p(div("You can:",style = "text-align: left;")),
                                     p(tags$div(icon("caret-right"), " Press the ", strong("'Check concentration matrix'"), " button to visualize them.", style = "text-align: left;")),
                                     p(tags$div(icon("caret-right"), " Filter and imputate them in the ", strong("next step."), style = "text-align: left;")),
                                   )
      )
    }
    
  })


  ######### STEP NA filtering and imputation ####


  stephwith = mod_imputation_step_server("imputation_step_lipsearch_with", parent = session, stepg = stepg, data_type = "Concentration")
  
  stephwithout = mod_imputation_step_server("imputation_step_lipsearch_without", parent = session, stepg = stepg, data_type = "Area")
  
  steph = reactive({
    if(input$type_lipsearch == 'No'){
      stephwithout()
    }else{
      stephwith()
    }
  })



  ######## Create sumexp object from LIQUID ########
  
  ##### STEP 1.
  ####import target and internal files xlsx
  
  #targetfile
  targetfile_to_edit_liquid = reactive({
    req(input$targetfile_liquid)
    ext <- tools::file_ext(input$targetfile_liquid$name)
    if(ext != "xlsx"){
      shinyWidgets::show_alert("Invalid file!", "Please upload a .xlsx file", type = "error")
    }
    validate(need(ext == "xlsx", "Invalid file! Please upload a .xlsx file"))
    x = tibble::as_tibble(openxlsx::read.xlsx(input$targetfile_liquid$datapath, na.strings = c("", "NA"), sep.names = " "))
    #x$Exp_date = lubridate::as_date(x$Exp_date)
    return(x)
  })
  
  
  targetfile_edit_liquid = mod_edit_data_server("edit_target_liquid", data_input = targetfile_to_edit_liquid)
  
  
  #internal standard
  internalstd_to_edit_liquid = reactive({
    req(input$internalstdpath_liquid)
    ext <- tools::file_ext(input$internalstdpath_liquid$name)
    if(ext != "xlsx"){
      shinyWidgets::show_alert("Invalid file!", "Please upload a .xlsx file", type = "error")
    }
    validate(need(ext == "xlsx", "Invalid file! Please upload a .xlsx file"))
    tibble::as_tibble(openxlsx::read.xlsx(input$internalstdpath_liquid$datapath, na.strings = c("", "NA"), sep.names = " "))
  })
  
  internalstd_edit_liquid = mod_edit_data_server("edit_internal_liquid", data_input = internalstd_to_edit_liquid)
  
  
  
  targets_liquid = reactive({
    req(targetfile_edit_liquid(), internalstd_edit_liquid())
    list(
      targetfile_lipidomics = targetfile_edit_liquid(),
      internal_standard = internalstd_edit_liquid()
    )
  })
  
  
  ###### STEP 2.
  #check data correctly loaded
  output$checktargets_liquid = reactive(
    return(is.null(targets_liquid()))
  )
  outputOptions(output, "checktargets_liquid", suspendWhenHidden = FALSE)
  
  
  ####select the data folder where to read data
  
  # this makes the directory at the base of your computer.
  volumes = c(Home = fs::path_home(), shinyFiles::getVolumes()())
  
  shinyFiles::shinyDirChoose(input, 'datafolder_liquid', roots = volumes, session = session)
  
  data_path_liquid = reactive({
    if(length(input$datafolder_liquid) != 1 ) {
      shinyFiles::parseDirPath(volumes,input$datafolder_liquid)
    }else{
      NULL
    }
  })
  
  
  stepb_liquid = eventReactive(input$readdatabttn_liquid,{
    req(data_path_liquid(), targets_liquid(), analysis())
    
    stepa = list(targets = targets_liquid(), analysis = analysis())
    withProgress(message = "Reading data...", value=0, {
      
      read_advise_lipidomics(
        out = stepa,
        datapath = data_path_liquid(),
        target_file = stepa$targets$targetfile_lipidomics,
        data_type = "Liquid")
    })
    
  })
  
  #stepb take the lipid_data path (ex. AF-1C-M_deuterated_1.txt) and targetfile and load all files.
  #stepb_liquid()$lipid_data
  #stepb_liquid()$replicates  TRUE if there are replicates otherwise FALSE
  
  
  #check data correctly loaded
  output$checkdatafiles_liquid = reactive(
    return(is.null(stepb_liquid()))
  )
  outputOptions(output, "checkdatafiles_liquid", suspendWhenHidden = FALSE)
  
  
  ####quality check
  output$qualcheckplot_liquid = renderPlotly({
    req(stepb_liquid())
    
    lipid_nonfilt = stepb_liquid()$lipid_data
    area = lapply(lipid_nonfilt, function(x) log2(sum(x$Intensity))) %>% tibble::as_tibble() %>% t() %>% as.data.frame() %>% tibble::rownames_to_column()
    colnames(area) = c("Samples", "Intensity")
    
    hh = ggplot(area) + geom_col(aes(x= Samples, y = Intensity)) + ylab("Log2(Intensity)") + 
      theme(axis.text.x = element_text(angle = 270, hjust = 0, size = 8))
    ggplotly(hh)
  })
  
  
  #######filtering options
  

  
  stepc_liquid = eventReactive(input$gofilterbttn_liquid,{
    req(stepb_liquid())
    filter_advise_lipidomics(
      out = stepb_liquid(),
      ca_bound = input$ca_bound_liquid,
      db_bound = input$db_bound_liquid,
      data_type = "Liquid"
    )
  })
  
  #stepc_liquid() take internal standard in targets() and lipid_data in readed_data() and filters them.
  #stepc_liquid()$lipid_filtered
  #stepc_liquid()$lipid_deuterated

  
  ###check end of filtering box
  output$checkendfiltering_liquid = reactive(
    return(is.null(stepc_liquid()))
  )
  outputOptions(output, "checkendfiltering_liquid", suspendWhenHidden = FALSE)
  
  
  observeEvent(stepc_liquid(),{
    updateSelectInput(session, "selcol_lipidfilt_liquid", choices = names(stepc_liquid()$lipid_filtered))
  })
  
  output$dtlipidfilterd_liquid = DT::renderDT({
    req(stepc_liquid())
    stepc_liquid()$lipid_filtered %>% purrr::pluck(input$selcol_lipidfilt_liquid)
  })
  
  
  
  ####PART 1.
  
  stepg_liquid = reactive({
    req(stepc_liquid())
    
    data_list_liquid <- lapply(stepc_liquid()$lipid_filtered, function(x) x %>%
                                 dplyr::select(Common_Name, Intensity))
    
    data_updated = list()
    for(k in 1:length(data_list_liquid)){
      data_updated[k] = list(data_list_liquid[[k]] %>% dplyr::rename(!!names(data_list_liquid)[k] := "Intensity"))
    }
    
    merged = data_updated %>% purrr::reduce(dplyr::full_join, by = "Common_Name") %>% 
      dplyr::rename("Lipids" = "Common_Name")
    
    #return stepg_liquid$concentration_matrix with everything else
    list(stepc_liquid(), concentration_matrix = list(concentration_matrix = merged)) %>% purrr::flatten()
    
    
  })
  
  
  
  #check data correctly loaded
  output$checkstepg_liquid = reactive(
    return(is.null(stepg_liquid()))
  )
  outputOptions(output, "checkstepg_liquid", suspendWhenHidden = FALSE)
  
  observeEvent(stepg_liquid(),{
    num_na = sum(is.na(stepg_liquid()$concentration_matrix))
    not_na = sum(!is.na(stepg_liquid()$concentration_matrix))
    
    if (num_na/(num_na+not_na) > 0.5){
      shinyWidgets::sendSweetAlert(session, title = "Too many NAs", type = "warning", width = "600px",
                                   text = tags$div(
                                     p(tags$div("More than 50% of the calibration matrix data are NAs.", style = "font-weight: bold;")),
                                     p(div("You can:",style = "text-align: left;")),
                                     p(tags$div(icon("caret-right"), " Press the ", strong("'Check concentration matrix'"), " button to visualize them.", style = "text-align: left;")),
                                     p(tags$div(icon("caret-right"), " Filter and imputate them in the ", strong("next step."), style = "text-align: left;")),
                                   )
      )
    }
    
  })
  
  
  stephliquid = mod_imputation_step_server("imputation_step_liquid", parent = session, stepg = stepg_liquid, data_type = "Peak Intensity")
  
  
  
  ######### Create sumexp object from Metabolomics Workbench #####
  
  mwdata = eventReactive(input$loadmw,{
    req(input$selmwid)
    showNotification(tagList(icon("cogs"), HTML("&nbsp;Downloading data from Metabolomics Workbench...")), type = "default")
    query = metabolomicsWorkbenchR::do_query('study','study_id', input$selmwid,'SummarizedExperiment')
    showNotification(tagList(icon("check"), HTML(paste0("&nbsp;Download of ",input$selmwid, " completed."))), type = "message")
    return(query)
  })
  
  #se tutti i data sono stati caricati
  output$checkmw = reactive(
    return(is.null(mwdata()))
  )
  outputOptions(output, "checkmw", suspendWhenHidden = FALSE)
  
  
  #assay
  mwassay = reactive({
    req(mwdata())
    if(input$selmwid == "ST000608"){
      asss = list()
      for(i in 1:2){
        roww = mwdata()[[i]] %>% SummarizedExperiment::rowData() %>% as.data.frame() %>% dplyr::select(metabolite_id, metabolite_name)
        aux_assay = mwdata()[[i]] %>% assay() %>% tibble::rownames_to_column("metabolite_id")
        aux_assay = dplyr::left_join(roww, aux_assay, by = "metabolite_id") %>% 
          dplyr::select(-metabolite_id) %>% dplyr::rename(Lipids = metabolite_name)
        rownames(aux_assay) = aux_assay$Lipids
        asss[[i]] = aux_assay
      }
      tot_ass = rbind(asss[[1]],asss[[2]])
      lip1 = stringr::str_replace(tot_ass$Lipids,";.*","")
      lip2 = stringr::str_replace(lip1,"_.*","")
      lip3 = stringr::str_replace(lip2, "PE\\(P-", "PEP\\(")
      index_L = grep("(?=^PE|PC|PS|PI|PG.*$)(?=.*\\b0:0\\b)",lip3, perl = T)
      lip3[index_L] = gsub("0:0/|/0:0", "", lip3[index_L])
      lip3[index_L] = paste0("L",lip3[index_L])
      tot_ass$Lipids = lip3
      aux_assay = tot_ass %>% dplyr::group_by(Lipids) %>% dplyr::summarise(dplyr::across(where(is.double), mean, na.rm = T)) %>% 
        as.data.frame()
    }else{
      roww = mwdata() %>% SummarizedExperiment::rowData() %>% as.data.frame() %>% dplyr::select(metabolite_id, metabolite_name)
      aux_assay = mwdata() %>% SummarizedExperiment::assay() %>% tibble::rownames_to_column("metabolite_id")
      aux_assay = dplyr::left_join(roww, aux_assay, by = "metabolite_id") %>% 
        dplyr::select(-metabolite_id) %>% dplyr::rename(Lipids = metabolite_name)
      #removing QC
      if(input$selmwid == "ST001073"){
        aux_assay = aux_assay %>% dplyr::select(!dplyr::starts_with("QC"))
      }
    }
    
    rownames(aux_assay) = aux_assay$Lipids
    if(input$selmwid == "ST001115" || input$selmwid == "ST000608"){
      sample_corrected = stringr::str_split_fixed(colnames(aux_assay[,-1]), "_",n = 3)
      sample_corrected = paste(paste(sample_corrected[,1], sample_corrected[,2], sep = "-"), sample_corrected[,3], sep = "_")
      colnames(aux_assay) = c("Lipids", sample_corrected)
    }
    aux_assay
  })
  
  #check na
  output$check_naassay_MW = reactive({
    req(mwassay())
    x = mwassay() %>% dplyr::select(where(is.double))
    num_na = sum(is.na(x))
    #not_na = sum(!is.na(x))
    if(num_na != 0){
      shinyWidgets::sendSweetAlert(session, title = "Missing values!", type = "warning", width = "600px",
                                   text = div("There are some missing values. Clustering, Dimensionality reduction and 
                                              Enrichment Analysis may not work.You should filter and impute 
                     them in order to prevent errors.", style = "font-weight: bold;"))
      TRUE
    }
  })
  outputOptions(output, "check_naassay_MW", suspendWhenHidden = FALSE)
  
  
  #### Check filtering
  filterstep_MW = eventReactive(input$gofilterna_MW,{
    req(mwassay())
    #filtered assay
    filt2 = list(concentration_matrix = as.data.frame(mwassay()))
    na_advise_lipidomics(
      out = filt2,
      na_filter_lip = as.numeric(input$na_filt_lip_ass_MW),
      na_filter_sam = as.numeric(input$na_filt_sam_ass_MW),
      imputation_met = "none"
    )
  })
  
  output$dt_filteredna_MW = renderDT({
    req(filterstep_MW())
    filterstep_MW()$concentration_matrix_filt
  })
  
  output$vimplot_filteredna_MW = renderPlot({
    req(filterstep_MW())
    filterstep_MW()$concentration_matrix_filt %>% dplyr::select(-1) %>% 
      VIM::aggr(combined = input$vimopz_filt_MW, cex.axis = 0.7, cex.lab = 0.7)
  })
  
  #box table dimensions after na filtering
  output$nadim1_MW = shinydashboard::renderInfoBox({
    dim = dim(filterstep_MW()$concentration_matrix[,-1])
    shinydashboard::infoBox(
      title = div(HTML(paste0("Table dimension", br(), "before filtering")), style = "color:white; font-size:100%;"),
      value = div(paste0(dim[1], " x ", dim[2]), style = "font-size:140%"),
      icon = icon("table"), color = "yellow", fill = TRUE)
  })
  
  output$nadim2_MW = shinydashboard::renderInfoBox({
    dim = dim(filterstep_MW()$concentration_matrix_filt[,-1])
    shinydashboard::infoBox(
      title = div(HTML(paste("Table dimension", br(), "after filtering")), style = "color:white; font-size:100%;"),
      value = div(paste0(dim[1], " x ", dim[2]), style = "font-size:140%"),
      icon = icon("table"), color = "green", fill = TRUE)
  })
  
  
  
  #### Create final output SumExp 
  sumexp_mw = eventReactive(input$make_sumexp_MW,{
    req(mwassay())
    #filtered assay
    filt2 = list(concentration_matrix = as.data.frame(mwassay()))
    if(input$togglefilterna_ass_MW == FALSE){
      filt = na_advise_lipidomics(
        out = filt2,
        na_filter_lip = 1,
        na_filter_sam = 1,
        imputation_met = "none"
      )
    }else{
      filt = na_advise_lipidomics(
        out = filt2,
        na_filter_lip = as.numeric(input$na_filt_lip_ass_MW),
        na_filter_sam = as.numeric(input$na_filt_sam_ass_MW),
        imputation_met = input$imput_method_ass_MW
      )
    }


    anal = list(
      lab_analyst = input$inlab_analyst,
      data_analyst = input$indata_analyst,
      pipe_ver = utils::packageVersion("ADViSELipidomics"), #"0.3.0", #golem::get_golem_version(),
      analysis_date = date()
    )
    
    if(input$selmwid == "ST000608"){
      coldata = mwdata()[[1]] %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
        dplyr::mutate(Sample_Type = gsub(" ","",Sample_Type))
    }
    
    if(input$selmwid == "ST001073"){
      #removing QC
      coldata = mwdata() %>% SummarizedExperiment::colData() %>% 
        as.data.frame() %>% dplyr::filter(!grepl("QC",local_sample_id)) %>% 
        dplyr::mutate(Crush = gsub(" ","",Crush))
    }
    
    if(input$selmwid == "ST001115"){
      coldata = mwdata() %>% SummarizedExperiment::colData() %>% 
        as.data.frame() %>% dplyr::mutate(Fraction = gsub(" ","",Fraction))
    }

    
    workbench_advise_lipidomics(filtered = filt, 
                                coldata = coldata,
                                metadata = anal,
                                data_type = input$typedata_assay_MW,
                                id = input$selmwid)
    
  })
  
  
  #check data correctly loaded
  output$checkstepmw = reactive(
    return(is.null(sumexp_mw()))
  )
  outputOptions(output, "checkstepmw", suspendWhenHidden = FALSE)
  
  
  observeEvent(input$gotosumexp_from_MW, {
    shinydashboard::updateTabItems(session, "sidebarmenu", "seedatatab")
  })
  
######### Create sumexp object from excel #####
  
  ###### COLDATA
  cold = reactive({
    req(input$coldatainput)
    ext <- tools::file_ext(input$coldatainput$name)
    if(ext != "xlsx"){
      shinyWidgets::show_alert("Invalid file!", "Please upload a .xlsx file", type = "error")
    }
    validate(need(ext == "xlsx", "Invalid file! Please upload a .xlsx file"))
    tibble::as_tibble(openxlsx::read.xlsx(input$coldatainput$datapath, na.strings = c("", "NA"), sep.names = " "))
    
  })
  
  
  observeEvent(cold(),{
    if(!"SampleID" %in% colnames(cold())){
      showNotification(tagList(icon("times-circle"), HTML("&nbsp;Required 'SampleID' column. Check if exists.")), type = "error")
    }
    if(length(cold()) == 1){
      showNotification(tagList(icon("times-circle"), HTML("&nbsp;Something wrong in reading. Check the delimiter.")), type = "error")
    }
  })
  
  
  #check data correctly loaded
  output$checkcold = reactive(
    if("SampleID" %in% colnames(cold()) & length(cold()) > 1){
      showNotification(tagList(icon("check"), HTML("&nbsp;Target file loaded correctly!")), type = "message")
      FALSE #instead of is.null(), so if it's null returns TRUE
    }
  )
  outputOptions(output, "checkcold", suspendWhenHidden = FALSE)
  
  cold2 = reactive({
    req(cold())
    validate(need("SampleID" %in% colnames(cold()), "Required 'SampleID' column. Check if exists."))
    validate(need(length(cold()) > 1, "Something wrong in reading. Check the delimiter."))
    cold()
  })
  
  ###### ASSAY ##
  
  ass = reactive({
    req(input$assayinput)
    ext <- tools::file_ext(input$assayinput$name)
    if(ext != "xlsx"){
      shinyWidgets::show_alert("Invalid file!", "Please upload a .xlsx file", type = "error")
    }
    validate(need(ext == "xlsx", "Invalid file! Please upload a .xlsx file"))
    tibble::as_tibble(openxlsx::read.xlsx(input$assayinput$datapath, na.strings = c("", "NA"), sep.names = " "))
  })
  
  
  observeEvent(ass(),{
    if(!"Lipids" %in% colnames(ass())){
      showNotification(tagList(icon("times-circle"), HTML("&nbsp;Required 'Lipids' column. Check if exists.")), type = "error")
    }
    if(length(ass()) == 1){
      showNotification(tagList(icon("times-circle"), HTML("&nbsp;Something wrong in reading. Check the delimiter.")), type = "error")
    }
  })
  
  
  #check data correctly loaded
  output$checkassay = reactive(
    if("Lipids" %in% colnames(ass()) & length(ass()) > 1){
      showNotification(tagList(icon("check"), HTML("&nbsp;Assay loaded correctly!")), type = "message")
      FALSE #al posto di is.null() che se è null restituisce TRUE
    }
  )
  outputOptions(output, "checkassay", suspendWhenHidden = FALSE)
  
  #check
  output$check_naassay = reactive({
    x = ass() %>% as.data.frame() %>% dplyr::select(where(is.double))
    num_na = sum(is.na(x))
    if(num_na != 0){
      shinyWidgets::sendSweetAlert(session, title = "Missing values!", type = "warning", width = "600px",
                                   text = div("There are some missing values. Clustering, Dimensionality reduction and 
                                              Enrichment Analysis may not work.You should filter and impute 
                     them in order to prevent errors.", style = "font-weight: bold;"))
      TRUE
    }
  })
  outputOptions(output, "check_naassay", suspendWhenHidden = FALSE)
  
  
  ass2 = reactive({
    req(ass())
    validate(need("Lipids" %in% colnames(ass()), "Required 'Lipids' column. Check if exists."))
    validate(need(length(ass()) > 1, "Something wrong in reading. Check the delimiter."))
    ass()
  })
  
  
  #### Check filtering NA
  filterstep_csv = eventReactive(input$gofilterna_csv,{
    req(ass2())
    #filtered assay
    filt2 = list(concentration_matrix = as.data.frame(ass2()))
    na_advise_lipidomics(
      out = filt2,
      na_filter_lip = as.numeric(input$na_filt_lip_ass),
      na_filter_sam = as.numeric(input$na_filt_sam_ass),
      imputation_met = "none"
    )
  })
  
  
  output$dt_filteredna_csv = renderDT({
    req(filterstep_csv())
    filterstep_csv()$concentration_matrix_filt
  })
  
  output$vimplot_filteredna_csv = renderPlot({
    req(filterstep_csv())
    filterstep_csv()$concentration_matrix_filt %>% dplyr::select(-1) %>% 
      VIM::aggr(combined = input$vimopz_filt_csv, cex.axis = 0.7, cex.lab = 0.7)
  })
  
  #box table dimensions after na filtering
  output$nadim1_csv = shinydashboard::renderInfoBox({
    dim = dim(filterstep_csv()$concentration_matrix[,-1])
    shinydashboard::infoBox(
      title = div(HTML(paste0("Table dimension", br(), "before filtering")), style = "color:white; font-size:100%;"),
      value = div(paste0(dim[1], " x ", dim[2]), style = "font-size:140%"),
      icon = icon("table"), color = "yellow", fill = TRUE)
  })
  
  output$nadim2_csv = shinydashboard::renderInfoBox({
    dim = dim(filterstep_csv()$concentration_matrix_filt[,-1])
    shinydashboard::infoBox(
      title = div(HTML(paste("Table dimension", br(), "after filtering")), style = "color:white; font-size:100%;"),
      value = div(paste0(dim[1], " x ", dim[2]), style = "font-size:140%"),
      icon = icon("table"), color = "green", fill = TRUE)
  })
  
  
  #### Final output SumExp
  sumexp_csv = eventReactive(input$make_sumexpcsv,{
    req(ass2(), cold2())
    #filtered assay
    filt2 = list(concentration_matrix = as.data.frame(ass2()))
    if(input$togglefilterna_ass == FALSE){
      filt = na_advise_lipidomics(
        out = filt2,
        na_filter_lip = 1,
        na_filter_sam = 1,
        imputation_met = "none"
      )
    }else{
      filt = na_advise_lipidomics(
        out = filt2,
        na_filter_lip = as.numeric(input$na_filt_lip_ass),
        na_filter_sam = as.numeric(input$na_filt_sam_ass),
        imputation_met = input$imput_method_ass
      )
    }
    
    #replicates
    tec_rep2 = stringr::str_count(cold2()$SampleID, "_")
    if(sum(tec_rep2) != 0){
      tec_rep = TRUE
    }else{
      tec_rep = FALSE
    }
    
    anal = list(
      lab_analyst = input$inlab_analyst,
      data_analyst = input$indata_analyst,
      pipe_ver = utils::packageVersion("ADViSELipidomics"), #"0.5.0", #golem::get_golem_version(),
      analysis_date = date()
    )
    
    out = purrr::flatten(
      list(filt,
           replicates = tec_rep,
           analysis = list(analysis = anal),
           targ = list(targets = list(targetfile_lipidomics = cold2()))
      )
    )
    
    sumexp_advise_lipidomics(out)
  })
  
  
  #check data correctly loaded
  output$checkstepcsv = reactive(
    return(is.null(sumexp_csv()))
  )
  outputOptions(output, "checkstepcsv", suspendWhenHidden = FALSE)
  
  observeEvent(input$gotosumexp_from_csv, {
    shinydashboard::updateTabItems(session, "sidebarmenu", "seedatatab")
  })
  
  
  #### Download handler for the download button
  output$downloadsumexp_csv <- downloadHandler(
    #put the file name with also the file extension
    filename = function() {
      paste0("summ_EXP_", Sys.Date(), ".rds")
    },
    
    # This function should write data to a file given to it by the argument 'file'.
    content = function(file) {
      summ = list(sumexp_data = sumexp_csv()$sumexp_data, 
                  sumexp_data_mean = sumexp_csv()$sumexp_data_mean, 
                  replicates = sumexp_csv()$replicates, 
                  data_type = input$typedata_assay)
      saveRDS(summ, file)
    }
  )
  
  
  
#____________________________________________________________________________
  
  output$checksteph = reactive(
    tryCatch({
      is.null(steph())
    },
    shiny.silent.error = function(e) {
      TRUE
    })
  )


  ####selection for the sumexp object (from file or step or csv) ####
  
  #import sumexp
  sumexp_import = reactive({
    req(input$finalsumexpinput)
    ext <- tools::file_ext(input$finalsumexpinput$name)
    if(ext != "rds"){
      shinyWidgets::show_alert("Invalid file!", "Please upload a .rds file", type = "error")
    }
    validate(need(ext == "rds", "Invalid file! Please upload a .rds file"))
    file = readRDS(file = input$finalsumexpinput$datapath)
    if(!is.null(file)){
      showNotification(tagList(icon("check"), HTML("&nbsp;Summarize Experiment successfully loaded!")), type = "message")
      return(file)
    }
  })
  

  
  sumexp_all_2 = reactive({
    checksumimport = tryCatch({sumexp_import()
      FALSE
    },shiny.silent.error = function(e) {TRUE})
    
    checkcsv = tryCatch({sumexp_csv()
      FALSE
    },shiny.silent.error = function(e) {TRUE})
    
    checksteph = tryCatch({steph()
      FALSE
    },shiny.silent.error = function(e) {TRUE})
    
    checkmw = tryCatch({sumexp_mw()
      FALSE
    },shiny.silent.error = function(e) {TRUE})
    
    checkliquid = tryCatch({stephliquid()
      FALSE
    },shiny.silent.error = function(e) {TRUE})
    
    
    
    if(input$sel_inputdata_type == "lipidsearch" && checksteph == FALSE){
      if(input$type_lipsearch == "Yes"){
        type = "Concentration"
      }else{
        type = "Area"
      }
      list(sumexp_data = steph()$sumexp_data, sumexp_data_mean = steph()$sumexp_data_mean, replicates = steph()$replicates, data_type = type)
    }else if(input$sel_inputdata_type == "excel" && checkcsv == FALSE){
      list(sumexp_data = sumexp_csv()$sumexp_data, sumexp_data_mean = sumexp_csv()$sumexp_data_mean, replicates = sumexp_csv()$replicates, data_type = input$typedata_assay)
    }else if(input$sel_inputdata_type == "sumexp" && checksumimport == FALSE){
      sumexp_import()
    }else if(input$sel_inputdata_type == "mw" && checkmw == FALSE){
      sumexp_mw()
    }else if(input$sel_inputdata_type == "liquid" && checkliquid == FALSE){
      list(sumexp_data = stephliquid()$sumexp_data, 
           sumexp_data_mean = stephliquid()$sumexp_data_mean, 
           replicates = stephliquid()$replicates, 
           data_type = "Peak Intensity")
    }
  })
  
  observeEvent(sumexp_all_2(),{
    updateSelectInput(session, "filt_by_target", choices = colnames(SummarizedExperiment::colData(sumexp_all_2()$sumexp_data)))
    updateSelectInput(session, "filt_by_lipids", choices = unique(SummarizedExperiment::rowData(sumexp_all_2()$sumexp_data)$Class))
  })
  
  observeEvent(input$filt_by_target,{
    if(!is.null(sumexp_all_2())){
      updateSelectInput(session, "filt_by_target_values", choices = unique(SummarizedExperiment::colData(sumexp_all_2()$sumexp_data)[,input$filt_by_target]))
    }
  })
  
  

  sumexp_filt = eventReactive(input$gofilt_sumexp,{
    req(sumexp_all_2())
    
    if(is.null(input$filt_by_target_values) && is.null(input$filt_by_lipids)){
      shinyWidgets::show_alert(title = "Nothing to filter!", type = "warning", width = "600px",
                               text = div("Please select something in the sample filtering or in the lipid class filtering.",
                                          style = "font-weight: bold;"))
      return(NULL)
    }else{
      filter_sumexp(data = sumexp_all_2(),
                    filt_targ = input$filt_by_target,
                    value_targ = input$filt_by_target_values,
                    filt_class = input$filt_by_lipids)
    }
  })
  

  
  output$check_filt = reactive({
    tryCatch({is.null(sumexp_filt())},
                        shiny.silent.error = function(e) {
                          return(TRUE)
                        })
  })
  outputOptions(output, "check_filt", suspendWhenHidden = FALSE)
  
  sumexp_all = reactive({
    req(sumexp_all_2())
    check_filt = tryCatch({is.null(sumexp_filt())},
             shiny.silent.error = function(e) {
               return(TRUE)
             })
    if(check_filt == FALSE){
      sumexp_filt()
    }else{
      sumexp_all_2()
    }
  })
  

  #### Download handler for the download button
  output$down_filtsumexp <- downloadHandler(
    #put the file name with also the file extension
    filename = function() {
      paste0("summ_EXP_filtered_", Sys.Date(), ".rds")
    },

    # This function should write data to a file given to it by the argument 'file'.
    content = function(file) {
      saveRDS(sumexp_filt(), file)
    }
  )
  


  sumexpdata = reactive({
    req(sumexp_all())
    sumexp_all()$sumexp_data
  })
  
  
  sumexpdatamean = reactive({
    req(sumexp_all())
    sumexp_all()$sumexp_data_mean
  })
  
  #check data correctly loaded
  output$check_replicates = reactive({
    req(sumexp_all())
    sumexp_all()$replicates  #TRUE if there are replicates
  })
  outputOptions(output, "check_replicates", suspendWhenHidden = FALSE)


  output$dtsumexp = renderDT({
    req(sumexpdata())
    if(input$summ_viewtable == TRUE && sumexp_all()$replicates == TRUE){
      x = sumexpdatamean()
    }else{
      x = sumexpdata()
    }
    if(input$sumexpselectobj == "colData"){
      SummarizedExperiment::colData(x) %>% as.data.frame()
    }else if(input$sumexpselectobj == "assays"){
      SummarizedExperiment::assay(x) %>% as.data.frame() %>% 
        DT::datatable(options = list(lengthMenu = c(10, 15, 25, 50), pageLength = 15, scrollX = TRUE, scrollY = 700))
    }else if(input$sumexpselectobj == "rowData"){
      row = SummarizedExperiment::rowData(x) %>% as.data.frame()
      temp = gsub(").*", ")", row$Lipids)
      temp = gsub("_","/", temp)
      row$Lipids = temp
      render <- c(
        "function(data, type, row){",
        "  if(type === 'display' && data){",
        "    var a = '<a href=\"http://www.swisslipids.org/#/search/' + data + '\">' + data + '</a>';",
        "    return a;",
        "  } else {",
        "    return data;",
        "  }",
        "}"
      )
      DT::datatable(row, rownames = T, 
                options = list(
                  lengthMenu = c(10, 15, 25, 50), pageLength = 15, scrollX = TRUE, scrollY = 700,
                  columnDefs = list(
                    list(targets = 1, render = DT::JS(render)),
                    list(targets = "_all", className = "dt-center")
                  )
                )
      )
    }else{
      x@metadata %>% as.data.frame()
    }
  },options = list(scrollX = TRUE, scrollY = 700, scrollCollapse = TRUE, lengthMenu = c(10, 15, 25, 50), pageLength = 15))



  


  #######PCA ########


  pcadata = eventReactive(input$gopca,{
    req(sumexpdata())
    if(input$summarize_pca == TRUE && sumexp_all()$replicates == TRUE){
      data = SummarizedExperiment::assay(sumexpdatamean()) %>% t()
    }else{
      data = SummarizedExperiment::assay(sumexpdata()) %>% t()
    }
    
    if(input$logpcalc == TRUE){
      data = log2(data)
    }
    g = try(stats::prcomp(data, scale = input$scalepcalc))
    if(inherits(g, "try-error")){
      showNotification(paste0("Error in performing PCA. ",g[1]), type = "error")
      return(NULL)
    }else{
      showNotification("PCA performed.")
      return(g)
    }
  })

  observeEvent(pcadata(),{
    pcs = colnames(pcadata()$rotation)[1:10] #take first 10 pcs
    pcs  = pcs[!is.na(pcs)] #if there are less than 10pcs, remove the NA generated
    updateSelectInput(session, "firstPC", choices = pcs)
    #updateSelectInput(session, "secondPC", choices = pcs)
  })
  
  observeEvent(input$firstPC,{
    pcs = colnames(pcadata()$rotation)[1:10] #take first 10 pcs
    pcs  = pcs[!is.na(pcs)] #if there are less than 10pcs, remove the NA generated
    updateSelectInput(session, "secondPC", choices = pcs[!pcs %in% input$firstPC])
  })

  
  #slider for PCs choice
  output$sliderpclc <- renderUI({
    req(pcadata())
    pca = pcadata()
    sliderInput("selpcslc", "Number of Principal Components (PC)", min=1, max=length(pca$sdev), value=2, step = 1)
  })


  output$pcantopui = renderUI({
    req(pcadata())
    max = pcadata()$rotation[,1] %>% length()
    numericInput("ntop_loadings", paste0("ntop ", "(from 1 to ", max, " )"), value = 25, min = 1, max = max)
  })

  ###plot loadings
  output$loadingslc = plotly::renderPlotly({
    req(pcadata(), input$selpcslc)
    pca = pcadata()
    loadpca = as.data.frame(pca$rotation[, input$selpcslc]) #invece di loadings ci sono i rotation
    loadpca = tibble::rownames_to_column(loadpca)

    pcasdev = as.data.frame(round(pca$sdev^2/sum(pca$sdev^2)*100, 2))
    colnames(loadpca) = c("Compounds", paste0("PC", input$selpcslc))
    ###ordering
    loadpca = loadpca %>% dplyr::arrange(desc(abs(loadpca[,2])))
    loadpca$Compounds = factor(loadpca$Compounds, levels = loadpca$Compounds)

    #ntop
    loadpca = loadpca[1:input$ntop_loadings,]

    loadplot = ggplot(loadpca, aes(x = Compounds, y = loadpca[,2], fill = Compounds)) + geom_col() +
      labs(y = paste0("PC", input$selpcslc, " ", "(", pcasdev[as.numeric(input$selpcslc), ], "%", ")"), title = "Loadings") +
      theme(axis.text.x = element_text(angle = 315, hjust = 0))
    plotly::ggplotly(loadplot)
  })

  ###screeplot
  output$screeplotlc <- plotly::renderPlotly({
    req(pcadata())
    pca = pcadata()
    var = cumsum(100*pca$sdev^2/sum(pca$sdev^2))
    var = as.data.frame(cbind(var)) %>% tibble::rownames_to_column()
    colnames(var) = c("Principal_components", "Explained_variation")
    var$Principal_components = factor(var$Principal_components, levels = c(1:length(var$Principal_components)))


    screegg = ggplot(var, aes(Principal_components,Explained_variation)) +
      geom_line(colour = "red", group = 1, linetype = "dashed", size = 1) + geom_point(size = 4, colour = "red") +
      labs(x = "Principal components", y = "Explained variation (%)", title = "Screeplot") +
      scale_y_continuous(limits = c(0, 100), breaks = c(seq(0, 100, by = 10)))
    plotly::ggplotly(screegg)

  })

  
  pcadata_info = eventReactive(input$gopca,{
    req(pcadata())
    if(input$summarize_pca == TRUE && sumexp_all()$replicates == TRUE){
      coll = SummarizedExperiment::colData(sumexpdatamean()) %>% as.data.frame() %>% tibble::rownames_to_column() 
    }else{
      coll = SummarizedExperiment::colData(sumexpdata()) %>% as.data.frame() %>% tibble::rownames_to_column()
    }
    

    tjoin = pcadata()$x %>% as.data.frame() %>% tibble::rownames_to_column()
    
    dplyr::inner_join(tjoin, coll, by = "rowname") %>% tibble::column_to_rownames("rowname")
    
  })
  

  observeEvent(pcadata_info(), {
    data = colnames(dplyr::select(pcadata_info(), -dplyr::starts_with("PC")))
    if("Product_Batch" %in% data){
      sel = "Product_Batch"
    }else{sel = data[1]}
    updateSelectInput(session, "shpbiplotlc", choices = data, selected = sel)
    updateSelectInput(session, "colbiplotlc", choices = data, selected = sel)
    updateSelectInput(session, "col3dlc", choices = data)
  })

  ###### DA FARE L'UPDATE DI SLIDERINPUT
  observeEvent(pcadata(),{
    updateSliderInput(session, "N_filt_biplot", min = 1, max = length(pcadata()$center))
  })
  
  ###biplot
  output$biplotlc = plotly::renderPlotly({
    req(pcadata(), input$colbiplotlc, pcadata_info())
    data_info = pcadata_info()
    pcadata = pcadata()
    
    data_info[,input$shpbiplotlc] = as.factor(data_info[,input$shpbiplotlc])
    data_info[,input$colbiplotlc] = as.factor(data_info[,input$colbiplotlc])
    x_axs = as.numeric(gsub("PC", "", input$firstPC))
    y_axs = as.numeric(gsub("PC", "", input$secondPC))
    
    if(input$selbiplotlc == "Biplot"){
      
      #reduce the number of arrows
      if(input$filt_biplot == TRUE){
        loadpca = as.data.frame(pcadata$rotation[, c(x_axs,y_axs)]) #invece di loadings ci sono i rotation
        pc1 = rownames(dplyr::arrange(loadpca, desc(abs(loadpca[,1])))[1:input$N_filt_biplot,])
        pc2 = rownames(dplyr::arrange(loadpca, desc(abs(loadpca[,2])))[1:input$N_filt_biplot,])
        lipids = unique(c(pc1,pc2))
        
        pcadata$rotation = as.data.frame(pcadata$rotation) %>% tibble::rownames_to_column("Lipids") %>% dplyr::filter(Lipids %in% lipids) %>%
          tibble::column_to_rownames("Lipids")
        pcadata$center = pcadata$center[lipids]
        pcadata$scale = pcadata$scale[lipids]
      }

      
      
      temp = autoplot(pcadata, x = x_axs, y = y_axs, data = data_info, shape = input$shpbiplotlc, colour = input$colbiplotlc, loadings = TRUE, loadings.colour = 'blue',
                      loadings.label = TRUE, loadings.label.size = 3, title = "Biplot") + theme(legend.title = element_blank())
    }else{
      temp = autoplot(pcadata, x = x_axs, y = y_axs, title = "Plot", data = data_info, shape = input$shpbiplotlc, colour = input$colbiplotlc) +
        theme(legend.title = element_blank())
    }

    plotly::ggplotly(temp) %>% plotly::layout(legend = list(title = list(text = paste(input$colbiplotlc, input$shpbiplotlc, sep = ", "))))
  })


  ### plot 3D
  output$pca3dlc = plotly::renderPlotly({
    req(pcadata_info())
    data_info = pcadata_info()
    data_info[,input$col3dlc] = as.factor(data_info[,input$col3dlc])
    data_info %>% plotly::plot_ly(x = ~PC1, y = ~PC2, z= ~PC3, color = ~base::get(input$col3dlc), type = "scatter3d", mode = "markers") %>% 
      plotly::layout(legend = list(title = list(text = input$col3dlc)))
  })


####### Plots #####


  #####lipid class distribution plots
  output$lipidsplot = renderUI({
    req(sumexpdata())

    lipids = SummarizedExperiment::rowData(sumexpdata())$Lipids %>% stringr::str_split_fixed(pattern = "\\(", 2)  #\\( perchè è un carattere speciale
    lipids = lipids[,1] %>% as.data.frame()
    colnames(lipids) = "Lipid"

    if(input$selplotlip == 1){
      output$pie1 = plotly::renderPlotly({
        lipids %>% plotly::plot_ly(labels = ~Lipid, type= "pie", textposition = 'inside', textinfo = 'label+value',
                                   marker = list(line = list(color = '#FFFFFF', width = 1)),
                                   showlegend = FALSE, width = "600px") %>% plotly::layout(title = "Lipid class distribution")
      })
      plotly::plotlyOutput("pie1")
    } else if(input$selplotlip == 2){
      output$bar1 = plotly::renderPlotly({
        getPalette = grDevices::colorRampPalette(RColorBrewer::brewer.pal(12, "Paired"))

        dd = ggplot(data= lipids) + geom_bar(mapping = aes(x = Lipid, fill = Lipid)) +
          scale_y_continuous(breaks = scales::pretty_breaks()) + ggtitle("Lipid class distribution") +
          xlab("Lipids") + labs(fill="Lipid Classes") + theme(axis.title = element_text(face="bold", size = 13), axis.text.x = element_text(angle = 315, hjust = 0, size = 11)) +
          scale_fill_manual(values = getPalette(length(unique(lipids$Lipid))))

      })
      plotly::plotlyOutput("bar1", width = "80%")
    } else{
      # Spider plot
      output$assaggispider = renderPlot({
        tab = table(lipids) %>% as.data.frame()
        gggg = data.frame(rbind(tab$Freq))
        colnames(gggg) = paste(tab$lipids)
        maxx = max(tab$Freq)
        max2 = maxx
        while(max2%%5 != 0){
          max2 = max2+1
        }

        g2 = rbind("Max" = max2, "Min" = 0, gggg)
        rownames(g2) <- c("Max", "Min", "freq")

        lab = c(0, max2*2/10, max2*4/10, max2*6/10, max2*8/10, max2)

        create_beautiful_radarchart(g2,  caxislabels = lab, color = grDevices::hcl.colors(2, palette = "Dynamic"), title = "Lipid class distribution")

      }, width = 800, height = 600)
      plotOutput("assaggispider")
    }
  })
  
  
  
  ##### taxa barplot lipid classes
  
  data_for_taxa = reactive({
    req(sumexpdata())
    if(input$summ_taxabar == TRUE && sumexp_all()$replicates == TRUE){
      sumexpdatamean()
    }else{
      sumexpdata()
    }
  })
  
  observeEvent(data_for_taxa(),{
    updateSelectInput(session, "annot_taxa", choices = c("No", colnames(SummarizedExperiment::colData(data_for_taxa()))))
  })
  
  output$taxabarplot = plotly::renderPlotly({
    req(data_for_taxa())
    size = ifelse(input$summ_taxabar == TRUE, 10, 7.5)

    data1 = data_for_taxa()

    taxabar = data1 %>% assay() %>% tibble::rownames_to_column("Lipids") %>% 
      dplyr::mutate(Lipids = gsub("\\(.*", "", Lipids)) %>% dplyr::rename(Class = Lipids)
    
    taxa_long = taxabar %>% tidyr::pivot_longer(cols = 2:length(taxabar), names_to = "SampleID", values_to = "Concentration")
    taxa_long2 = taxa_long %>% dplyr::group_by(Class, SampleID) %>% dplyr::summarise(dplyr::across(Concentration, ~sum(.x, na.rm = TRUE)))
    
    if(input$annot_taxa != "No"){
      
      coldata = data_for_taxa() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
        dplyr::select(SampleID, input$annot_taxa)
      taxa_long2 = dplyr::left_join(taxa_long2, coldata, by = "SampleID")

      taxa = ggplot(taxa_long2, aes(x = SampleID, y = Concentration, fill = Class)) + geom_col(position = "fill") + 
        scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) + ggtitle("Lipid class proportion") + 
        facet_wrap(~get(input$annot_taxa), scales = "free_x", strip.position =  "top") + ylab(paste(sumexp_all()$data_type, "proportion")) +
        theme(axis.text.x = element_text(angle = 315, hjust = 0, size = size, margin=margin(t=30)),legend.title = element_blank())
    }else{
      taxa = ggplot(taxa_long2, aes(x = SampleID, y = Concentration, fill = Class)) + geom_col(position = "fill") + 
        scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) + ylab(paste(sumexp_all()$data_type, "proportion")) +
        ggtitle("Lipid class proportion") + 
        theme(axis.text.x = element_text(angle = 315, hjust = 0, size = size),legend.title = element_blank())
    }

    plotly::ggplotly(taxa)
  })



  output$taxabarplot_ui = renderUI({
    req(data_for_taxa())
    plotly::plotlyOutput("taxabarplot", height = paste0(input$height_taxa,"px"))
    
  })
  ##### lipid species distribution barplot #####
  
  
  observeEvent(data_for_taxa(),{
    #lipids class
    updateSelectInput(session, "class_spec_dist", choices = unique(SummarizedExperiment::rowData(data_for_taxa())$Class))
    
    #fill var
    coln = data_for_taxa() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% dplyr::select(!where(is.numeric)) %>% colnames()
    if("Product_Batch" %in% coln){
      sel = "Product_Batch"
    }else{sel = coln[1]}
    
    updateSelectInput(session, "fill_spec_dist", choices = coln, selected = sel)
    
    coln2 = data_for_taxa() %>% SummarizedExperiment::colData() %>% as.data.frame()%>% colnames()
    if("Product_Batch" %in% coln2){
      sel2 = "Product_Batch"
    }else{sel2 = coln2[1]}
    updateSelectInput(session, "facet_spec_var", choices = coln2, selected = sel2)
  })
  
  
  
  output$lipspec_barplot = renderPlotly({
    req(data_for_taxa())
    
    ass_mean = SummarizedExperiment::assay(data_for_taxa())
    
    rowd = SummarizedExperiment::rowData(data_for_taxa()) %>% as.data.frame() %>% dplyr::select(Lipids, Class)
    ass_mean2 = ass_mean %>% as.data.frame() %>% tibble::rownames_to_column("Lipids") %>% dplyr::left_join(rowd, by = "Lipids")
    
    
    #filter by class
    cold_mean = SummarizedExperiment::colData(data_for_taxa()) %>% as.data.frame()
    
    ass_mean_filt = ass_mean2 %>% dplyr::filter(Class == input$class_spec_dist) %>% dplyr::select(-Class) %>% 
      tibble::column_to_rownames("Lipids") %>% t() %>% as.data.frame() %>% tibble::rownames_to_column("SampleID") %>% 
      dplyr::left_join(dplyr::select(cold_mean, SampleID, input$fill_spec_dist,input$facet_spec_var), by = "SampleID") %>% 
      tidyr::pivot_longer(cols = !c(input$fill_spec_dist, input$facet_spec_var, SampleID), names_to = "Lipids", values_to = "Value")
    

    if(input$summ_spec_dist == TRUE){
      #summarized
      temp2 = ggplot(ass_mean_filt, aes_string(x="Lipids", y = "Value", fill = input$fill_spec_dist)) +
        geom_bar(position = position_dodge(), stat = "summary",fun = "mean") +
        stat_summary(geom = "errorbar", fun.data = mean_se, position = position_dodge2(padding = 1.6, preserve = "single")) +
        theme(axis.text.x = element_text(angle = 315, hjust = 0), legend.title = element_blank()) + ylab(sumexp_all()$data_type)
    }else{
      #not summarized
      temp2 = ggplot(ass_mean_filt, aes_string(x = "Lipids", y = "Value", fill = input$fill_spec_dist, label = "SampleID")) +
        geom_col(position = position_dodge2(preserve = "single")) + ylab(sumexp_all()$data_type) +
        theme(axis.text.x = element_text(angle = 315, hjust = 0), legend.title = element_blank())
    }
    
    if(input$facet_spec_dist == TRUE){
      
      temp2 = temp2 + facet_wrap(~get(input$facet_spec_var), strip.position = "top") #scales = "free",
    }
    
    if(input$flip_spec == TRUE){
      temp2 = temp2 + coord_flip()
    }


    plotly::ggplotly(temp2)
  })

  ######boxplot lipide (es. cer) contro condizioni (sulf, bc)



  observeEvent(sumexpdata(), {
    updateSelectInput(session, "select_lipidplot", choices = SummarizedExperiment::rowData(sumexpdata())$Lipids)
    
    if("Product_Batch" %in% colnames(SummarizedExperiment::colData(sumexpdata()))){
      sel = "Product_Batch"
    }else{sel = colnames(SummarizedExperiment::colData(sumexpdata()))[1]}
    updateSelectInput(session, "select_fillboxplot", choices = colnames(SummarizedExperiment::colData(sumexpdata())), selected = sel)
  })


  output$lipcondplot = renderPlotly({
    req(sumexpdata())
    if(input$summ_lipidboxplot == TRUE && sumexp_all()$replicates == TRUE){
      data1 = sumexpdatamean()
    }else{
      data1 = sumexpdata()
    }
    
    if(input$log_lipidboxplot == TRUE){
      data = SummarizedExperiment::assay(data1) %>% log2()
    }else{
      data = SummarizedExperiment::assay(data1)
    }
    
    ass = data %>% t() %>% as.data.frame() %>% tibble::rownames_to_column("sample")
    cold = SummarizedExperiment::colData(data1) %>% as.data.frame() %>% tibble::rownames_to_column("sample")

    joinedt1 = dplyr::inner_join(ass, cold, by = "sample")

    Concentration = joinedt1[, colnames(joinedt1) %in% input$select_lipidplot]

    jok = data.frame(dplyr::select(joinedt1, input$select_fillboxplot), Concentration)
    jok[,input$select_fillboxplot] = as.factor(jok[,input$select_fillboxplot])
    
    if(input$addpoints_lipidboxplot == FALSE){
      gg = ggplot(jok, aes_string(x = input$select_fillboxplot, y = "Concentration", fill = input$select_fillboxplot)) +
        geom_boxplot() + ylab(input$select_lipidplot)
    }else{
      gg = ggplot(jok, aes_string(x = input$select_fillboxplot, y = "Concentration", fill = input$select_fillboxplot)) +
        geom_boxplot() + geom_point() + geom_jitter(width = 0.2) + ylab(input$select_lipidplot) 
    }
    plotly::ggplotly(gg)
  })

  
  #####scatterplot sample vs sample
  samples_for_update = reactive({
    req(sumexpdata())
    if(input$summ_scatt == TRUE && sumexp_all()$replicates == TRUE){
      SummarizedExperiment::assay(sumexpdatamean()) %>% colnames()
    }else{
      SummarizedExperiment::assay(sumexpdata()) %>% colnames()
    }
  })

  observeEvent(samples_for_update(), {
    req(samples_for_update())
    updateSelectInput(session, "sel_sample1_scatt", choices = samples_for_update())
    updateSelectInput(session, "sel_sample2_scatt", choices = samples_for_update())
  })


  output$scattsampleplot = renderPlotly({
    req(samples_for_update())
    xlab = ifelse(input$log_scatt == FALSE, input$sel_sample1_scatt, paste0("Log2(", input$sel_sample1_scatt, ")"))
    ylab = ifelse(input$log_scatt == FALSE, input$sel_sample1_scatt, paste0("Log2(", input$sel_sample2_scatt, ")"))

    if(input$summ_scatt == TRUE && sumexp_all()$replicates == TRUE){
      assay = SummarizedExperiment::assay(sumexpdatamean())
    }else{
      assay = SummarizedExperiment::assay(sumexpdata()) 
    }
    assay = assay %>% tibble::rownames_to_column("Lipid")
    

    if(input$log_scatt == TRUE){
      assay = assay %>% dplyr::mutate(dplyr::across(where(is.numeric), log2))
      }
    
    gg = ggplot(assay, aes_string(x = paste0("`",input$sel_sample1_scatt,"`"), y = paste0("`",input$sel_sample2_scatt,"`"), color = "Lipid")) +
      geom_point() + theme(legend.title = element_blank()) + labs(x = xlab, y = ylab)
    plotly::ggplotly(gg) %>% plotly::layout(legend = list(title = list(text = "Lipids")))
  })

  
  
  ############ HEATMAP
  
  dataforheatmap = reactive({
    req(sumexp_all())
    if(sumexp_all()$replicates == TRUE){
      sumexpdatamean()
    }else{
      sumexpdata()
    }
  })
  #slider for columns
  output$sliderheatcol <- renderUI({
    req(dataforheatmap())
    len = SummarizedExperiment::rowData(dataforheatmap())$Class %>% unique() %>% length() #numero di lipidi (poi si ruota)
    sliderInput("slidercolheat", "Column cluster number:", min=2, max = len, value=2, step = 1)
  })
  
  #slider for rows
  output$sliderheatrow <- renderUI({
    req(dataforheatmap())
    len = SummarizedExperiment::colData(dataforheatmap())$SampleID %>% unique() %>% length() #numero di sample (poi si ruota)
    sliderInput("sliderrowheat", "Row cluster number:", min = 2, max = len, value = 2, step = 1)
  })
  
  
  
  #second filtering
  output$checkadd2filt_heat = reactive({
    if(input$add2filter_heat %%2 == 0){
      "onevar"
    }else{"twovar"}
  })
  outputOptions(output, "checkadd2filt_heat", suspendWhenHidden = FALSE)
  
  observeEvent(input$add2filter_heat,{
    if(input$add2filter_heat %%2 == 1){
      updateButton(session, "add2filter_heat",label = HTML("&nbsp;Remove"), style = "danger", icon("minus")) 
    }else{
      updateButton(session, "add2filter_heat", label = HTML("&nbsp;Add"), style="success", icon("plus"))
    }
  })
  
  
  observeEvent(dataforheatmap(),{
    if("Product_Batch" %in% colnames(SummarizedExperiment::colData(dataforheatmap()))){
      sel = "Product_Batch"
    }else{sel = colnames(SummarizedExperiment::colData(dataforheatmap()))[1]}
    updateSelectInput(session, "selectannot_row", choices = colnames(SummarizedExperiment::colData(dataforheatmap())), selected = sel)
    
    #rowdata without NA column
    rowdata = SummarizedExperiment::rowData(dataforheatmap())[,colSums(is.na(SummarizedExperiment::rowData(dataforheatmap())))<nrow(SummarizedExperiment::rowData(dataforheatmap()))] %>%
      colnames()
    if("Class" %in% rowdata){
      sel2 = "Class"
    }else{sel2 = rowdata[1]}
    updateSelectInput(session, "selectannot_col", choices = rowdata, selected = sel2)
    
    
    #filtering
    filtcols = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
      dplyr::select(where(~length(unique(.))>1)) %>% colnames()
    updateSelectInput(session, "filtheatmapcol",  choices =  filtcols)
    
    updateSelectInput(session, "filtheatmapcol2",  choices =  filtcols)
  })
  

  observeEvent(input$filtheatmapcol,{
    if(input$filtheatmapcol != "" && !is.null(input$filtheatmapcol)){
      vals = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
        dplyr::pull(input$filtheatmapcol) %>% unique()%>% as.character()
      updateSelectInput(session, "filtheatmapval",  choices = vals)
    }
  })
  
  observeEvent(input$filtheatmapcol2,{
    if(input$filtheatmapcol2 != "" && !is.null(input$filtheatmapcol2) && !is.null(input$filtheatmapval)){
      vals = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
        dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval) %>% 
        dplyr::pull(input$filtheatmapcol2) %>% unique()%>% as.character()
      updateSelectInput(session, "filtheatmapval2",  choices = vals)
    }
  })
  
  
  
  observeEvent(input$gofilter_heat,{
    if(!is.null(dataforheatmap()) && !is.null(input$filtheatmapval)){
      coldata = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
        dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval)
      
      #second filtering
      if(input$add2filter_heat %%2 == 1 && !is.null(input$filtheatmapval2)){
        coldata = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
          dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval & !!sym(input$filtheatmapcol2) %in% input$filtheatmapval2)
      }
      
      assay = dataforheatmap() %>% SummarizedExperiment::assay() %>% dplyr::select(rownames(coldata))
      if(dim(assay)[2] <= 1){
        shinyWidgets::show_alert(title ="Warning!",type = "warning",
                                 text = "Your filter returns a matrix with only one column. Dendrograms and scaling on column are disabled.")
        updateSelectInput(session, "selscaleheat", choices = c("None" = "none", "By row" = "row"))
        updateMaterialSwitch(session, "rowdend", value = FALSE)
        updateMaterialSwitch(session, "columndend", value = FALSE)
        shinyjs::disable("rowdend")
        shinyjs::disable("columndend")
      }else{
        shinyWidgets::show_alert(title ="Filter applied!",type = "success",
                                 text = "Your filter is correctly applied.")
        updateSelectInput(session, "selscaleheat", choices = c("None" = "none", "By row" = "row", "By column" = "column"))
        shinyjs::enable("rowdend")
        shinyjs::enable("columndend")
      }
    }
  })
  
  observeEvent(input$filter_heatmap,{
    if(input$filter_heatmap == FALSE){
      updateSelectInput(session, "selscaleheat", choices = c("None" = "none", "By row" = "row", "By column" = "column"))
    }
  })
  
  
  dataforheatmap_filtered = eventReactive(input$gofilter_heat,{
    req(dataforheatmap())
    if(is.null(input$filtheatmapval)){
      showNotification(tagList(icon("times-circle"), HTML("&nbsp;Select at least one value in the 'Value filtering'.")), type = "error")
    }
    validate(need(!is.null(input$filtheatmapval), "Select at least one value in the Value filtering."))
    coldata = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
      dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval)
    
    #second filtering
    if(input$add2filter_heat %%2 == 1){
      if(is.null(input$filtheatmapval2)){
        showNotification(tagList(icon("times-circle"), HTML("&nbsp;Select at least one value in the 'Value filtering' (2).")), type = "error")
      }else{
        validate(need(!is.null(input$filtheatmapval2), "Select at least one value in the Value filtering (2)."))
        coldata = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
          dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval & !!sym(input$filtheatmapcol2) %in% input$filtheatmapval2)
      }
    }

    
    assay = dataforheatmap() %>% SummarizedExperiment::assay() %>% dplyr::select(rownames(coldata))
    list(coldata = coldata, 
         assay = assay, 
         rowdata = dataforheatmap() %>% SummarizedExperiment::rowData())
  })


  
  dataheat = eventReactive(input$makeheatmap,{
    req(dataforheatmap())
    #filter data?
    if(input$filter_heatmap == TRUE){
      validate(need(!is.null(input$filtheatmapval), "Select at least one value in the 'Value filtering'."))
      
      #check if gofilter_heat is clicked again
      coldata2 = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
        dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval)
      
      #second filtering
      if(input$add2filter_heat %%2 == 1 && !is.null(input$filtheatmapval2)){
        validate(need(!is.null(input$filtheatmapval2), "Select at least one value in the 'Value filtering' (2)."))
        coldata2 = dataforheatmap() %>% SummarizedExperiment::colData() %>% as.data.frame() %>% 
          dplyr::filter(!!sym(input$filtheatmapcol) %in% input$filtheatmapval & !!sym(input$filtheatmapcol2) %in% input$filtheatmapval2)
      }
      
      check_heatfilt = tryCatch({is.null(dataforheatmap_filtered())},
      shiny.silent.error = function(e) {return(TRUE)})

      if(check_heatfilt){
        show_alert("Warning!", "If you want to use a filter on data, be sure to apply it by clicking on the 'Apply filtering' button", type = "warning")
        return(NULL)
      }else if(!isTRUE(all.equal(coldata2, dataforheatmap_filtered()$coldata))){
        show_alert("Warning!", "You changed something in the data filtering without apply changes. Please click on the 'Apply filtering' button", type = "warning")
        return(NULL)
      }else{
        data_heat = dataforheatmap_filtered()
      }
      
    }else{
      data_heat = list(coldata = as.data.frame(SummarizedExperiment::colData(dataforheatmap())), 
           assay = SummarizedExperiment::assay(dataforheatmap()), 
           rowdata = dataforheatmap() %>% SummarizedExperiment::rowData())
    }
    
    make_heatmap(
      data = data_heat,
      #filter = c(input$filtheatmapcol, input$filtheatmapval),
      add_rowannot = input$selectannot_row,
      add_colannot = input$selectannot_col,
      log_data = input$logheat,
      scale_data = input$selscaleheat,
      order_data = input$heatsort,
      dist_method = input$seldistheat,
      clust_method = input$selhclustheat,
      row_dend = input$rowdend,
      row_nclust = input$sliderrowheat,
      col_dend = input$columndend,
      col_nclust = input$slidercolheat,
      padding = c(4,2,2,15),
      unit_legend = input$unitlegend_ht
    )
  })


  observeEvent(dataheat(),{
    if(!is.null(dataheat())){
      InteractiveComplexHeatmap::makeInteractiveComplexHeatmap(input, output, session, dataheat(), heatmap_id  = "heatmap_output")
    }
  })
  
  
  
  
  
  
  
#######Quality plots ######
  
  observeEvent(sumexpdata(), {
    #### SAMPLE
    #barplot density plot e boxplot
    if("Product_Batch" %in% colnames(SummarizedExperiment::colData(sumexpdata()))){
      sel = "Product_Batch"
    }else{sel = colnames(SummarizedExperiment::colData(sumexpdata()))[1]}
    updateSelectInput(session, "densplot_sampfill", choices = colnames(SummarizedExperiment::colData(sumexpdata())), selected = sel)

    ### LIPIDS
    #boxplot lipids
    
    if(sumexp_all()$replicates == TRUE){
      samples_id = SummarizedExperiment::colData(sumexpdatamean())$SampleID
    }else{
      samples_id = SummarizedExperiment::colData(sumexpdata())$SampleID
    }
    updateSelectInput(session, "concbox_samp", choices = samples_id)
    
    updateSelectInput(session, "concbox_sampfill", choices = c("Class", colnames(SummarizedExperiment::colData(sumexpdata()))))

    updateSelectInput(session, "concbox_samp2", choices = samples_id)
    updateSelectInput(session, "concbox_sampfill2", choices = c("Class", colnames(SummarizedExperiment::colData(sumexpdata()))))
  })
  
  
  #se ci sono replicati metto di default la spunta a summarize data
  observeEvent(sumexp_all(),{
    if(sumexp_all()$replicates == TRUE){
      updateAwesomeCheckbox(session, "summ_qualplot", value = TRUE)
    }
  })
  
  


  
  ####### Samples _____________________________________________________
  
  
  #Concentration Barplot (Samples)
  output$concbarplot_samp = renderPlotly({
    req(sumexpdata(), input$densplot_sampfill)
    
    if(input$summ_qualplot == TRUE && sumexp_all()$replicates == TRUE){
      se_data1 = sumexpdatamean()
    }else{
      se_data1 <- sumexpdata()
    }
    se_data = SummarizedExperiment::assay(se_data1)
    
    sum_data <- data.frame(Sum_conc = apply(se_data, 2, function(x) sum(x, na.rm = T)))
    if(input$plotsamp_log == TRUE){
      sum_data = log2(sum_data)
      y_sm = paste0("Log2(", sumexp_all()$data_type, " Sum)")
    } else {
      y_sm = paste0(sumexp_all()$data_type, " Sum)")
    }
    sum_data$SampleID <- factor(rownames(sum_data), levels = rownames(sum_data))
    sum_data <- merge(x = sum_data,
                      y = data.frame(SummarizedExperiment::colData(se_data1)[, c("SampleID", input$densplot_sampfill)]),
                      by = "SampleID", all.x = TRUE)
    sum_data[,input$densplot_sampfill] = as.factor(sum_data[,input$densplot_sampfill])

    sample_barplot <- ggplot2::ggplot(sum_data, aes_string(x = "SampleID", y = "Sum_conc", fill = input$densplot_sampfill)) +
      geom_bar(stat = "identity") +
      labs(x = "Samples", y = y_sm, title = paste0(sumexp_all()$data_type, " Barplot (Samples)")) +
      theme(axis.text.x = element_text(angle = -90, vjust = 0.5))
    

    plotly::ggplotly(sample_barplot)

  })

  
  #### sample boxplot sample with log conc #####
  output$boxplot_density = renderPlotly({
    req(sumexpdata())
    #se_data <- SummarizedExperiment::assay(sumexpdata())
    
    if(input$summ_qualplot == TRUE && sumexp_all()$replicates == TRUE){
      se_data1 = sumexpdatamean() 
    }else{
      se_data1 = sumexpdata()
    }
    se_data = SummarizedExperiment::assay(se_data1)

    box_data = log2(se_data)
    
    box_data = as.data.frame(t(box_data)) %>% tibble::rownames_to_column("Sample")
    

    box_data$temp <- SummarizedExperiment::colData(se_data1)[, input$densplot_sampfill]
    colnames(box_data)[colnames(box_data) == 'temp'] <- input$densplot_sampfill
    

    aux_name = box_data %>% dplyr::ungroup() %>% dplyr::select(-c("Sample", input$densplot_sampfill)) %>% colnames()
    box_data <- box_data %>% tidyr::gather(Lipid,Conc, all_of(aux_name)) #diventa long
    box_data <- cbind(box_data, Class = sapply(strsplit(box_data$Lipid,"\\("), `[`, 1))
    box_data[,input$densplot_sampfill] = as.factor(box_data[,input$densplot_sampfill])
    
    if(input$addpoints_boxdens == TRUE){
      au2 = ggplot(box_data, aes_string(y = "Conc",  x ="Sample", fill = input$densplot_sampfill)) + geom_boxplot() + 
        geom_point() + labs( y = "log2(Concentration)", title = "Boxplot") + coord_flip()
    }else{
      au2 = ggplot(box_data, aes_string(y = "Conc",  x ="Sample", fill = input$densplot_sampfill)) + geom_boxplot() + 
      labs( y = paste0("log2(",sumexp_all()$data_type,")"), title = "Boxplot") + coord_flip()
    }

    plotly::ggplotly(au2)
    
  })
  

  ##### density plot ##
  
  output$densplot_samp = plotly::renderPlotly({
    req(sumexpdata())

    if(input$summ_qualplot == TRUE && sumexp_all()$replicates == TRUE){
      se_data = SummarizedExperiment::assay(sumexpdatamean())
    }else{
      se_data = SummarizedExperiment::assay(sumexpdata()) 
    }
    
    box_data <- log2(se_data)
    box_data = as.data.frame(t(box_data)) %>% tibble::rownames_to_column("Sample")

    box_data = box_data %>% tidyr::gather(Lipid, Conc, all_of(colnames(box_data[,-1])))
    
    au2 = ggplot(box_data) + geom_density(aes_string(x = "Conc",  fill = "Sample"), alpha = 0.2) + 
      labs( x = paste0("log2(",sumexp_all()$data_type,")"), y = "density", title = "Density boxplot")
    
    plotly::ggplotly(au2)
  })
  
  
  ####### LIPIDS #_______________________________________________________________
  
    observeEvent(sumexpdata(),{
      updateSelectInput(session, "filtclass_concbar", choices = unique(SummarizedExperiment::rowData(sumexpdata())$Class))
    })
    
  # Concentration Barplot (Lipids)
  output$concbarplot_lip = renderPlotly({
    req(sumexpdata())

    se_data <- SummarizedExperiment::assay(sumexpdata())
    if(input$concbar_log == TRUE){
      cv_data = log2(se_data)
      y_cv = paste0("% CV Log2(",sumexp_all()$data_type,")")
    } else {
      cv_data = se_data
      y_cv = paste0("% CV ",sumexp_all()$data_type)
    }
    cv_data <- data.frame(cv_conc = apply(cv_data, 1, function(x) sd(as.numeric(x),na.rm = T)/mean(as.numeric(x), na.rm = T) * 100))
    cv_data$Lipid <- factor(rownames(cv_data), levels = rownames(cv_data))
    cv_data$Class <- SummarizedExperiment::rowData(sumexpdata())$Class
    if(!is.null(input$filtclass_concbar)){
      cv_data <- cv_data %>% dplyr::filter(Class %in% input$filtclass_concbar)
    }
    
    plot = ggplot2::ggplot(cv_data, aes(x = forcats::fct_rev(Lipid), y = cv_conc, fill = Class)) +
      geom_bar(stat = "identity") + labs(x = "Lipids", y = y_cv, title = paste0(sumexp_all()$data_type, " Barplot (Lipids)"))
    
    if(input$flip_concbar == TRUE){
      plot = plot + coord_flip() + theme(axis.text.y = element_text(size = 7))
    }else{
      plot = plot +theme(axis.text.x = element_text(angle = -90, size = 7))
    }
    
    plotly::ggplotly(plot)

  })

  output$concbarplot_lip_UI = renderUI({
    
    if(input$flip_concbar == TRUE){
      classes = SummarizedExperiment::rowData(sumexpdata()) %>% as.data.frame() 
      if(!is.null(input$filtclass_concbar)){
        classes <- classes %>% dplyr::filter(Class %in% input$filtclass_concbar)
      }
      nbars = dim(classes)[1]
      size_plot = 84 + (640*nbars)/(55 + nbars/10) #640 found with html inspect when 50 prod are shown.
      
      plotly::plotlyOutput("concbarplot_lip", height = paste0(size_plot,"px"))
    }else{
      plotly::plotlyOutput("concbarplot_lip", height = "600px")
    }
  })
  
  #Plots: Concentration Boxplot (Lipids)
  output$concboxplot_samp = renderPlotly({
    req(sumexpdata())

    se_data <- SummarizedExperiment::assay(sumexpdata())

    if(input$concbox_log == TRUE){
      box_data = log2(se_data)
      y_box = paste0("Log2(",sumexp_all()$data_type," Sum)")
    } else {
      box_data = se_data
      y_box = paste0(sumexp_all()$data_type," Sum")
    }

    box_data <- as.data.frame(t(box_data)) %>% tibble::rownames_to_column("Sample") %>%
      tidyr::separate(Sample, into = c("Sample", "rep"), sep = "_", fill = "right") %>% dplyr::select(-rep) %>%
      dplyr::group_by(Sample)
    if(input$concbox_sampfill != "Class"){
      box_data$temp <- as.factor(SummarizedExperiment::colData(sumexpdata())[, input$concbox_sampfill])
      colnames(box_data)[colnames(box_data) == 'temp'] <- input$concbox_sampfill
    }

    aux_name <- colnames(box_data)[-c(1,dim(box_data)[2])]
    box_data <- box_data %>% tidyr::gather(Lipid,Conc,all_of(aux_name))
    box_data <- cbind(box_data, Class = sapply(strsplit(box_data$Lipid,"\\("), `[`, 1))

    bx_data2 = dplyr::filter(box_data, Sample == input$concbox_samp)

    if(input$concbox_points == FALSE){
     plot = ggplot2::ggplot(bx_data2, aes_string(x = "Class", y = "Conc", fill = input$concbox_sampfill)) +geom_boxplot() +
      labs(y = y_box, title = paste0(sumexp_all()$data_type, " Boxplot (Lipids)")) 
    }else{
      plot = ggplot2::ggplot(bx_data2, aes_string(x = "Class", y = "Conc", fill = input$concbox_sampfill)) + geom_boxplot() +
        geom_point() + geom_jitter(width = 0.2) + labs( y = y_box, title = paste0(sumexp_all()$data_type, " Boxplot (Lipids)")) 
    }

    plotly::ggplotly(plot)

  })

  #second boxplot
  output$concboxplot_samp2 = renderPlotly({
    req(sumexpdata())

    se_data <- SummarizedExperiment::assay(sumexpdata())

    if(input$concbox_log2 == TRUE){
      box_data = log2(se_data)
      y_box = paste0("Log2(",sumexp_all()$data_type," Sum)")
    } else {
      box_data = se_data
      y_box = paste0(sumexp_all()$data_type," Sum")
    }

    box_data <- as.data.frame(t(box_data)) %>% tibble::rownames_to_column("Sample") %>%
      tidyr::separate(Sample, into = c("Sample", "rep"), sep = "_", fill = "right") %>% dplyr::select(-rep) %>%
      dplyr::group_by(Sample)
    if(input$concbox_sampfill2 != "Class"){
      box_data$temp <- SummarizedExperiment::colData(sumexpdata())[, input$concbox_sampfill2]
      colnames(box_data)[colnames(box_data) == 'temp'] <- input$concbox_sampfill2
    }

    aux_name <- colnames(box_data)[-c(1,dim(box_data)[2])]
    box_data <- box_data %>% tidyr::gather(Lipid,Conc,all_of(aux_name))
    box_data <- cbind(box_data, Class = sapply(strsplit(box_data$Lipid,"\\("), `[`, 1))

    bx_data2 = dplyr::filter(box_data, Sample == input$concbox_samp2)
    
    if(input$concbox_points2 == FALSE){
      plot = ggplot2::ggplot(bx_data2, aes_string(x = "Class", y = "Conc", fill = input$concbox_sampfill2)) +geom_boxplot() +
      labs( y = y_box, title = paste0(sumexp_all()$data_type, " Boxplot (Lipids)"))
    }else{
      plot = ggplot2::ggplot(bx_data2, aes_string(x = "Class", y = "Conc", fill = input$concbox_sampfill2)) +geom_boxplot() +
        geom_point() + geom_jitter(width = 0.2) + labs( y = y_box, title = paste0(sumexp_all()$data_type, " Boxplot (Lipids)"))
    }
    
    plotly::ggplotly(plot)

  })



#### Clustering #####
  
  sumexpde_forclust = reactive({
    req(sumexp_all())
    if(input$cluster_summar == FALSE){
      data = sumexp_all()$sumexp_data
    }else{
      data = sumexp_all()$sumexp_data_mean
    }
    if(input$clust_transp == "Samples"){
      data = data %>% SummarizedExperiment::assay() %>% t()
    }else{
      data = data %>% SummarizedExperiment::assay()
    }

    if(input$clust_scale == TRUE){
      scale(data)
    }else{data}
  })
  


  #check if distance matrix can be calculated
  output$check_clustering = reactive({
    req(sumexpde_forclust())
    if(input$selclustmethod == "Partitioning"){
      clust = try(stats::kmeans(sumexpde_forclust(), centers = 2, nstart = 25))
    }else{
      clust = try(factoextra::eclust(sumexpde_forclust(), "hclust", stand = FALSE,  k = 2))
      }
    inherits(clust, "try-error")
  })
  outputOptions(output, "check_clustering", suspendWhenHidden = FALSE)

  
  # plots for clusters number choice
  output$numclustergraph = renderPlot({
    req(sumexpde_forclust())
    
    if(input$selclusthmorfo == "K-means"){
      p1 = factoextra::fviz_nbclust(sumexpde_forclust(), stats::kmeans, method = "gap_stat")
      p2 = factoextra::fviz_nbclust(sumexpde_forclust(), stats::kmeans, method = "wss")
      p3 = factoextra::fviz_nbclust(sumexpde_forclust(), stats::kmeans, method = "silhouette")
    } else if(input$selclusthmorfo == "PAM"){
      p1 = factoextra::fviz_nbclust(sumexpde_forclust(), cluster::pam, method = "gap_stat")
      p2 = factoextra::fviz_nbclust(sumexpde_forclust(), cluster::pam, method = "wss")
      p3 = factoextra::fviz_nbclust(sumexpde_forclust(), cluster::pam, method = "silhouette")
    } else{
      p1 = factoextra::fviz_nbclust(sumexpde_forclust(), cluster::clara, method = "gap_stat")
      p2 = factoextra::fviz_nbclust(sumexpde_forclust(), cluster::clara, method = "wss")
      p3 = factoextra::fviz_nbclust(sumexpde_forclust(), cluster::clara, method = "silhouette")
    }
    
    if(input$selclustmethod == "Partitioning"){
      gridExtra::grid.arrange(p1, p2, p3, ncol = 2)
    } else{
      meth = c("single","complete","ward.D","ward.D2")
      d = stats::dist(sumexpde_forclust())
      par(mfrow=c(2,2))
      for(i in seq(1,4)){
        hs = stats::hclust(d, method = meth[i])
        plot(hs$height, pch=16, main = meth[i], ylab = "Height")
      }
    }
  })
  
  #data cluster
  output$plotcluster = renderPlot({
    req(sumexpde_forclust())
    if(input$selclustmethod == "Partitioning"){
      if(input$selclusthmorfo == "K-means"){
        clust = stats::kmeans(sumexpde_forclust(), centers = input$selnumclust, nstart = 25)
      } else if (input$selclusthmorfo == "PAM"){
        clust = cluster::pam(sumexpde_forclust(), k = input$selnumclust)
      } else {
        clust = cluster::clara(sumexpde_forclust(), k = input$selnumclust)
      }
      factoextra::fviz_cluster(clust, data = sumexpde_forclust(), stand = FALSE, 
                               ellipse.type = "t", palette = "jco", ggtheme = theme_minimal())
    } else {
      hcluster = factoextra::eclust(sumexpde_forclust(), "hclust", stand = FALSE, hc_method = input$selhclustmeth, k = input$selnumclust)
      p1 = factoextra::fviz_dend(hcluster, palette = "jco", rect = TRUE, show_labels = T, cex = 0.7, ggtheme = theme_minimal())
      p2 = factoextra::fviz_silhouette(hcluster)
      gridExtra::grid.arrange(p1, p2, ncol = 2)
    }
  })
  
  
  
    ##### EXP Design #####
  sumexpde_forcoldata = reactive({
    req(sumexp_all())
    if(input$expdes_summar == TRUE && sumexp_all()$replicates == TRUE){
      sumexpdatamean()
    }else{
      sumexpdata()
    }
  })
  
  
  final_contrast = mod_write_contrasts_server("write_contrasts_1", 
                                              sumexp = sumexpde_forcoldata, 
                                              is_batch_removed = reactive(FALSE),
                                              Batch_Options = NULL)


  observeEvent(sumexp_all(),{
    if(sumexp_all()$data_type != "Concentration"){
      updateAwesomeRadio(session, "expdes_bs_norm", choices = c("none", "scale", "quantile"), inline = TRUE)
    }else{
      updateAwesomeRadio(session, "expdes_bs_norm", choices = c("none", "scale"), inline = TRUE)
    }
  })
  
  
  #expdes_summar
  expdesign = eventReactive(input$runDE,{
    req(sumexp_all(), final_contrast())

    #se non ci sono repliche faccio finta che sia mediato
    if(sumexp_all()$replicates == FALSE){
      exp_summ = TRUE
    }else{
      exp_summ = input$expdes_summar
    }

    exp1 = expdesign_advise_lipidomics(
      out = sumexp_all(),
      design_vars = final_contrast()$varsde,
      rep_mean = exp_summ,
      file_contrast = final_contrast()$file_cont,
      batch_type = final_contrast()$batch_type,
      batch_vars = final_contrast()$batches,
      batch_method = final_contrast()$batch_meth
      )
    tryCatch({
      diffexp_advise_lipidomics(
        out = exp1,
        rep_mean = exp_summ,
        rep_effect = input$expdes_repeffect,
        bs_norm = input$expdes_bs_norm,
        batch_vars = final_contrast()$batches,
        batch_type = final_contrast()$batch_type,
        batch_method = final_contrast()$batch_meth,
        thresh = input$expdes_thresh,
        decide_met = input$expdes_decide_met
      )
    },error = function(err){
      if(err$message == "No residual degrees of freedom in linear model fits"){
        shinyWidgets::show_alert("No residual degrees of freedom in linear model fits.
                               We suggest to use the model with replicates.", type = "error")
      }else{
        shinyWidgets::show_alert(paste0(err), type = "error")
      }

    })

  })


  
  output$checktoptable = reactive(
    is.null(expdesign()$limma_result)
  )
  outputOptions(output, "checktoptable", suspendWhenHidden = FALSE)
  


  observeEvent(expdesign(), {
    contrast = c(colnames(expdesign()$contrast_matrix))
    names(contrast) = gsub("vs"," vs ", contrast)
    
    updateSelectInput(session, "expdes_colmaplot", choices = contrast)
    updateSelectInput(session, "sel_toptable", choices = contrast)
  })
  
  output$toptable = DT::renderDT({
    req(expdesign(), input$sel_toptable)
    expdesign()$limma_result[[input$sel_toptable]]
  })
  
  #### Download handler for the download button
  output$downloadtoptable <- downloadHandler(
    #put the file name with also the file extension
    filename = function() {
      paste0("TopTable", Sys.Date(), ".xlsx")
    },
    
    # This function should write data to a file given to it by the argument 'file'.
    content = function(file) {
      openxlsx::write.xlsx(expdesign()$limma_result[[input$sel_toptable]], file)
    }
  )
  


  expdes_data_forplot = reactive({
    req(expdesign(), input$expdes_colmaplot)
    expdesign()$limma_result[[input$expdes_colmaplot]]
  })


  #Add another volcano button
  output$checkadd2volcano = reactive({
    if(input$addmorevolcanos %%2 == 0){"onevolc"} else{"twovolc"}
  })
  outputOptions(output, "checkadd2volcano", suspendWhenHidden = FALSE)
  
  observeEvent(input$addmorevolcanos,{
    if(input$addmorevolcanos %%2 == 1){
      updateButton(session, "addmorevolcanos",label = HTML("&nbsp;Remove second plot"), style = "danger", icon("minus"))
    }else{
      updateButton(session, "addmorevolcanos", label = HTML("&nbsp;Add another plot"), style="success", icon("plus"))
    }
  })
  
  
  mod_ma_volcano_plot_server("ma_volcano_plot1",
                             data_input = expdes_data_forplot,
                             contrast = reactive(input$expdes_colmaplot),
                             logfc_val = reactive(input$expdes_lfc),
                             thresh = reactive(input$expdes_thresh))


  mod_ma_volcano_plot_server("ma_volcano_plot2",
                             data_input = expdes_data_forplot,
                             contrast = reactive(input$expdes_colmaplot),
                             logfc_val = reactive(input$expdes_lfc),
                             thresh = reactive(input$expdes_thresh))


  observeEvent(expdesign(),{
    contrast = c(colnames(expdesign()$test_result))
    names(contrast) = gsub("vs"," vs ", contrast)
    updateSelectInput(session, "venncontrast", choices = contrast, selected = contrast)
  })

# Differential expressed lipids Venn diagram
output$venndiag = renderUI({
  req(expdesign())
  test_result = expdesign()$test_result[,input$venncontrast]
  validate(
    need(ncol(test_result) >= 2 && ncol(test_result) <6, "Venn diagram for DC lipids is plotted from two to five contrasts!")
  )
    aux_con <- tibble::rownames_to_column(as.data.frame(test_result)) %>%
      dplyr::mutate_all(list(~dplyr::case_when(. != 0 ~ rowname,  TRUE ~ "0"))) %>%
      dplyr::select(-rowname)
    aux_con <- lapply(as.list(aux_con), function(x) x[x != "0"])
    venn <- ggVennDiagram::Venn(aux_con)
    data_venn <- ggVennDiagram::process_data(venn)

    output$vennplot = renderPlot({
      if(input$venngrad == TRUE){

      data_venn@setEdge$id <- rep("3",length(data_venn@setEdge$id))
      vd_plot <- ggVennDiagram::ggVennDiagram(aux_con,
                                              category.names = colnames(test_result),
                                              label_percent_digit = 1,
                                              label_alpha = 0,
                                              label_color = "black",
                                              edge_size = 0) +
        ggplot2::geom_sf(aes(color = id), data = ggVennDiagram::venn_setedge(data_venn), show.legend = FALSE) +
        ggplot2::scale_fill_gradient(low = "white", high = "blue") +
        ggplot2::scale_x_continuous(expand = expansion(mult = .2))

    } else {
      region_label <- data_venn@region %>%
        dplyr::filter(.data$component == "region") %>%
        dplyr::mutate(percent = paste(round(.data$count*100/sum(.data$count),
                                            digits = 1),"%", sep="")) %>%
        dplyr::mutate(both = paste(.data$count,paste0("(",.data$percent,")"),sep = "\n"))

      vd_plot <- ggplot() +
        geom_sf(aes(fill = id), data = ggVennDiagram::venn_region(data_venn), show.legend = FALSE) +
        geom_sf(color = "black", size = 1, data = ggVennDiagram::venn_setedge(data_venn), show.legend = FALSE) +
        geom_sf_text(aes(label = name), data = ggVennDiagram::venn_setlabel(data_venn)) +
        geom_sf_text(aes(label = both), data = region_label) +
        scale_x_continuous(expand = expansion(mult = .2)) +
        theme_void()

    }
    vd_plot
    })

    output$dtvenn = DT::renderDT({
      len <- max(sapply(data_venn@region$item, length)) ## get length of longest vector
      table_venn <- sapply(data_venn@region$item, function(x) `length<-`(unlist(x), len))
      colnames(table_venn) <-  gsub("\\.+","\U2229",data_venn@region$name)
      render <- c(
        "function(data, type, row){",
        "  if(type === 'display' && data){",
        "    var newstr = data.replace(/_/g, '/').replace(/\\).*/g, ')');",
        "    var a = '<a href=\"http://www.swisslipids.org/#/search/' + newstr + '\">' + data + '</a>';",
        "    return a;",
        "  } else {",
        "    return data;",
        "  }",
        "}"
      )
      DT::datatable(table_venn, rownames = F,
                options = list(
                  columnDefs = list(
                    list(targets = "_all", render = DT::JS(render)),
                    list(targets = "_all", className = "dt-center")
                  )
                )
      )
    },options = list("pageLength" = 15))

    fluidRow(
      column(5, br(), br(), br(), plotOutput("vennplot")),
      column(7, div(DT::DTOutput("dtvenn"), style = "overflow-y: scroll; overflow-x: scroll;"))
    )
})



output$upsetplot = renderPlot({
  req(expdesign())
  validate(
    need(length(colnames(expdesign()$test_result)) > 1, "Upset Plot for DC lipids is plotted from more than one contrast!")
  )
  validate(
    need(all(expdesign()$test_result == 0) == FALSE, "No DC Lipids into the contrasts.")
  )

  comb_mat <- ComplexHeatmap::make_comb_mat(abs(expdesign()$test_result))
  cs = ComplexHeatmap::comb_size(comb_mat)
  cm_degree = ComplexHeatmap::comb_degree(comb_mat)
  aux_color <- grDevices::colorRampPalette(RColorBrewer::brewer.pal(12,"Paired"))

  ht = ComplexHeatmap::UpSet(comb_mat, pt_size = grid::unit(5,"mm"), lwd = 3,
             comb_col = aux_color(length(cm_degree)),
             comb_order = order(cm_degree, -cs),
             top_annotation = HeatmapAnnotation(
               "Intersection size" = ComplexHeatmap::anno_barplot(cs,
                                                  ylim = c(0, max(cs)*1.1),
                                                  border = FALSE,
                                                  gp = grid::gpar(fill = aux_color(length(cm_degree))),
                                                  height = grid::unit(10, "cm")
               ),
               annotation_name_side = "left",
               annotation_name_rot = 0),
             right_annotation = ComplexHeatmap::upset_right_annotation(comb_mat, add_numbers = TRUE)
  )
  ht = ComplexHeatmap::draw(ht)
  od = ComplexHeatmap::column_order(ht)
  ComplexHeatmap::decorate_annotation("Intersection size", {
    grid::grid.text(cs[od], x = seq_along(cs), y = grid::unit(cs[od], "native") + grid::unit(4, "pt"),
              default.units = "native", just = c("center", "bottom"),
              gp = grid::gpar(fontsize = 10, col = "#404040"), rot = 0)
  })
})



##### Enrichment ####
observeEvent(expdesign(),{
  contrast = c(names(expdesign()$limma_result))
  names(contrast) = gsub("vs"," vs ", contrast)
  updateSelectInput(session, "enrich_selcont", choices = contrast)
})

output$enrich_plot = renderPlot({
  check = tryCatch({
    is.null(expdesign())
  },
  shiny.silent.error = function(e) {
    TRUE
  })
  
  validate(need(check == FALSE, "Enrichment Analysis requires the output from Differential Analysis. Please run first the Differential Analysis."))
  req(expdesign())
  enrichment_advise_lipidomics(
    out = expdesign(),
    rank_c = input$rank_c,
    thresh = input$enrich_thresh,
    k = input$enrich_selcont
  )

})


####### PLS-DA ######


sumexpde_forplsda = reactive({
  req(sumexp_all())
  if(input$summ_plsda == TRUE && sumexp_all()$replicates == TRUE){
    sumexpdatamean()
  }else{
    sumexpdata()
  }
})

observeEvent(sumexpde_forplsda(),{
  data = sumexpde_forplsda() %>% SummarizedExperiment::colData() %>% as.data.frame()
  #selectin columns with more than one level
  data = data[, sapply(data, function(col) length(unique(col))) > 1]
  if("Product_Batch" %in% colnames(data)){
    sel = "Product_Batch"
  }else{
    sel= colnames(data)[1]
  }
  updateSelectInput(session, "selcol_pls", choices = colnames(data), selected = sel)
})


#number of allowed components (usually K-1)
output$plsda_ncompui = renderUI({
  req(sumexpde_forplsda())
  Y = as.factor(colData(sumexpde_forplsda())[,input$selcol_pls])
  max = length(unique(Y))
  numericInput("plsda_ncomp", paste0("Number of components ", "(from 2 to ", max, " )"), value = 2, min = 1, max = max, step = 1)
})


#pls-da
plsda = eventReactive(input$gopls,{
  req(sumexpde_forplsda(), input$plsda_ncomp)
  X = sumexpde_forplsda() %>% SummarizedExperiment::assay() %>% as.matrix() %>% t()
  Y = as.factor(SummarizedExperiment::colData(sumexpde_forplsda())[,input$selcol_pls])
  if(nrow(X)<30){
    showNotification(tagList(icon("exclamation-circle"), HTML("&nbsp;There are less than 30 samples. PLS-DA could not be statistically significant.")), type = "warning")
  }
  mixOmics::plsda(X, Y, ncomp = input$plsda_ncomp)
})


#plotIndiv
output$plotindiv_pls = renderPlot({
  req(plsda())
  validate(need(input$plsda_ncomp > 1, "PLS-DA plots require at least 2 components."))
  if(input$pls_back_ellipse == "Background"){
    background <- mixOmics::background.predict(plsda(), comp.predicted = 2, dist = "max.dist")
    len = length(unique(plsda()$Y))
    if(len > 8){
      palette = grDevices::colorRampPalette(RColorBrewer::brewer.pal(8, name  = "Dark2"))
      colors = palette(len)
    }else{
      colors = RColorBrewer::brewer.pal(len, name  = "Dark2")
      colors = colors[1:len]
    }
    mixOmics::plotIndiv(plsda(), comp = 1:2, ind.names = input$indname_pls, legend = TRUE, background = background,
                        col = colors)
  }else if(input$pls_back_ellipse == "Ellipse"){
    mixOmics::plotIndiv(plsda(), ellipse = T, legend = T, ind.names = input$indname_pls)
  }else{
    mixOmics::plotIndiv(plsda(), legend = T, ind.names = input$indname_pls)
  }
})

output$plotvar_pls = renderPlot({
  req(plsda())
  validate(need(input$plsda_ncomp > 1, "PLS-DA plots require at least 2 components."))
  mixOmics::plotVar(plsda(), cex = 3.5)
})

perf.plsda = eventReactive(input$gotunepls,{
  req(sumexpde_forplsda(), input$selcol_pls, input$selfolds)
  X = sumexpde_forplsda() %>% SummarizedExperiment::assay() %>% as.matrix() %>% t()
  Y = as.factor(SummarizedExperiment::colData(sumexpde_forplsda())[,input$selcol_pls])

  plsda.res = mixOmics::plsda(X, Y, ncomp = length(unique(Y)))
  mixOmics::perf(plsda.res, validation = "Mfold", folds = input$selfolds,
       progressBar = TRUE, auc = TRUE, nrepeat = input$selnrepeat)#, cpus = parallel::detectCores(logical = F)-1)
})


output$perfplsda = renderPlot({
  req(perf.plsda())
  plot(perf.plsda(), col = mixOmics::color.mixo(5:7), sd = TRUE, legend.position = "horizontal")
})

output$bestncomp_pls = renderPrint({
  req(perf.plsda())
  perf.plsda()$choice.ncomp
  
})









####sPLS-DA #####


sumexpde_forsplsda = reactive({
  req(sumexp_all())
  if(input$summ_splsda == TRUE && sumexp_all()$replicates == TRUE){
    sumexpdatamean()
  }else{
    sumexpdata()
  }
})

observeEvent(sumexpde_forsplsda(),{
  data = sumexpde_forsplsda() %>% SummarizedExperiment::colData() %>% as.data.frame()
  #selectin columns with more than one level
  data = data[, sapply(data, function(col) length(unique(col))) > 1]
  if("Product_Batch" %in% colnames(data)){
    sel = "Product_Batch"
  }else{
    sel= colnames(data)[1]
  }
  updateSelectInput(session, "selcol_spls", choices = colnames(data), selected = sel)
})


#number of allowed components (usually K-1)
output$splsda_ncompui = renderUI({
  req(sumexpde_forsplsda())
  Y = as.factor(colData(sumexpde_forsplsda())[,input$selcol_spls])
  max = length(unique(Y))
  numericInput("splsda_ncomp", paste0("Number of components ", "(from 2 to ", max, " )"), value = 2, min = 1, max = max, step = 1)
})


#spls-da
splsda = eventReactive(input$gospls,{
  req(sumexpde_forsplsda(), input$splsda_ncomp, input$keepx_splsda)
  X = sumexpde_forsplsda() %>% SummarizedExperiment::assay() %>% as.matrix() %>% t()
  Y = as.factor(SummarizedExperiment::colData(sumexpde_forsplsda())[,input$selcol_spls])
  keepx = gsub(" ", "", input$keepx_splsda)
  keepx = strsplit(keepx,",", fixed = FALSE)[[1]] 
  keepx = as.numeric(keepx)
  validate(need(anyNA(keepx) == FALSE, "Error in KeepX. Please verify KeepX contains only numbers separated by a comma."))
  if(nrow(X)<30){
    showNotification(tagList(icon("exclamation-circle"), HTML("&nbsp;There are less than 30 samples. sPLS-DA could not be statistically significant.")), type = "warning")
  }
  mixOmics::splsda(X, Y, ncomp = input$splsda_ncomp, keepX = keepx)
})


#plotIndiv
output$plotindiv_spls = renderPlot({
  req(splsda())
  if(input$spls_back_ellipse == "Background"){
    background <- mixOmics::background.predict(splsda(), comp.predicted = 2, dist = "max.dist")
    len = length(unique(splsda()$Y))
    if(len > 8){
      palette = grDevices::colorRampPalette(RColorBrewer::brewer.pal(8, name  = "Dark2"))
      colors = palette(len)
    }else{
      colors = RColorBrewer::brewer.pal(len, name  = "Dark2")
      colors = colors[1:len]
    }
    
    mixOmics::plotIndiv(splsda(), comp = 1:2, ind.names = input$indname_spls, legend = TRUE, background = background,
                        col = colors)
  }else if(input$spls_back_ellipse == "Ellipse"){
    mixOmics::plotIndiv(splsda(), ellipse = T, legend = T, ind.names = input$indname_spls)
  }else{
    mixOmics::plotIndiv(splsda(), legend = T, ind.names = input$indname_spls)
  }
})



output$plotvar_spls = renderPlot({
  req(splsda())
  mixOmics::plotVar(splsda())
})




tune.splsda = eventReactive(input$gotunespls,{
  req(sumexpde_forsplsda(), input$selnrepeat_spls,input$selcol_spls)
  X = sumexpde_forsplsda() %>% SummarizedExperiment::assay() %>% as.matrix() %>% t()
  Y = as.factor(SummarizedExperiment::colData(sumexpde_forsplsda())[,input$selcol_spls])
  
  list.keepX <- c(5:10,  seq(20, 100, 10))
  mixOmics::tune.splsda(X, Y, ncomp = length(unique(Y)),
                        validation = 'Mfold', 
                        folds = input$selfolds_spls, 
                        dist = 'max.dist', progressBar = TRUE,
                        measure = "BER", test.keepX = list.keepX,
                        nrepeat = input$selnrepeat_spls)
})


output$plot_bestsparse = renderPlot({
  req(tune.splsda())
  n = dim(tune.splsda()$choice.ncomp$values)[2]
  plot(tune.splsda(), col = mixOmics::color.jet(n))
})


output$bestncomp_spls = renderPrint({
  req(tune.splsda())
  tune.splsda()$choice.ncomp$ncomp
})

output$bestkeepx_spls = renderPrint({
  req(tune.splsda())
  tune.splsda()$choice.keepX
})





}
ShinyFabio/ADViSELipidomics documentation built on March 21, 2023, 7:30 a.m.