#' Statmodel Server module for stat inference #' #' This function sets up the Statmodel server to process data based on user #' selected inputs #' #' @param input input object to capture different ui element values #' @param output to render and create elements #' @param session session current module #' @param parent_session session of the main calling module #' @param loadpage_input input object from loadpage UI #' @param qc_input input object from QC UI #' @param get_data stored function that returns the data from loadpage #' @param preprocess_data stored function that returns preprocessed data #' #' @return list object with user selected options and matrix build #' statmodelServer <- function(input, output, session,parent_session, loadpage_input, qc_input,get_data,preprocess_data) { ######### UI ######### # choices of groups for contrast matrix choices = reactive({ if (loadpage_input()$BIO == "PTM" & ((loadpage_input()$BIO == "PTM" & loadpage_input()$DDA_DIA == "TMT") | loadpage_input()$filetype=='phil')){ levels(preprocess_data()$PTM$ProteinLevelData$Condition) } else if(loadpage_input()$BIO == "PTM" & (loadpage_input()$BIO == "PTM" & loadpage_input()$DDA_DIA != "TMT")){ levels(preprocess_data()$PTM$ProteinLevelData$GROUP) } else if(loadpage_input()$DDA_DIA=="TMT"){ levels(preprocess_data()$ProteinLevelData$Condition) } else{ levels(preprocess_data()$ProteinLevelData$GROUP) } }) row = reactive({rep(0, length(choices()))}) contrast = reactiveValues() comp_list = reactiveValues() significant = reactiveValues() observe({ if(loadpage_input()$DDA_DIA == "TMT" | loadpage_input()$BIO == "PTM"){ hide("Design") } else{ shinyjs::show("Design") } }) output$choice1 = renderUI({ ns <- session$ns selectInput(ns("group1"), "Group 1", choices()) }) output$choice2 = renderUI({ ns <- session$ns selectInput(ns("group2"), "Group 2", choices()) }) output$choice3 = renderUI({ ns <- session$ns selectInput(ns("group3"), "", choices()) }) output$comp_name = renderUI({ ns <- session$ns textInput(ns("comp_name"), label = "Comparison Name", value = "") }) output$weights = renderUI({ ns <- session$ns lapply(1:length(choices()), function(i) { list( numericInput(ns(paste0("weight", i)), label = choices()[i], value=0)) }) }) # rownames for matrix Rownames = eventReactive(input$submit | input$submit1 | input$submit2 | input$submit3, { req(input$def_comp) req(loadpage_input()$DDA_DIA) tryCatch({ rownames(matrix_build())}, error=function(e){}) }) # choices of comparisons/proteins to plot output$WhichComp = renderUI ({ ns <- session$ns selectInput(ns("whichComp"), label = h5("Select comparison to plot"), c("all", Rownames()), selected = "all") }) output$WhichProt = renderUI ({ ns <- session$ns selectInput(ns("whichProt"), label = h4("which protein to plot"), unique(get_data()[[1]])) }) output$WhichProt1 = renderUI ({ ns <- session$ns selectizeInput(ns("whichProt1"), label = h4("which protein to plot"), c("", unique(get_data()[[1]]))) }) ########## functions ######## # build matrix observeEvent(input$def_comp, { contrast$matrix = NULL comp_list$dList = NULL }) observeEvent(loadpage_input()$proceed1, { contrast$matrix = NULL comp_list$dList = NULL significant$result = NULL }) ## Check contrast matrix was created correctly check_cond = eventReactive(input$submit | input$submit1 | input$submit2 | input$submit3, { req(input$def_comp) req(loadpage_input()$DDA_DIA) if(input$def_comp == "custom") { validate( need(input$group1 != input$group2, "Please select different groups") )} else if(input$def_comp == "custom_np") { wt_sum = 0 for (index in 1:length(choices())){ wt_sum = wt_sum + input[[paste0("weight", index)]] } validate( need( wt_sum == 0, "The contrast weights should sum up to 0") )} }) matrix_build = eventReactive(input$submit | input$submit1 | input$submit2 | input$submit3, { req(input$def_comp) req(loadpage_input()$DDA_DIA) if(input$def_comp == "custom") { if(input$group1 == input$group2){ return(contrast$matrix) } index1 = reactive({which(choices() == input$group1)}) index2 = reactive({which(choices() == input$group2)}) comp_list$dList = unique(c(isolate(comp_list$dList), paste(input$group1, "vs", input$group2, sep = " "))) contrast$row = matrix(row(), nrow=1) contrast$row[index1()] = 1 contrast$row[index2()] = -1 if (is.null(contrast$matrix)) { contrast$matrix = contrast$row } else { contrast$matrix = rbind(contrast$matrix, contrast$row) contrast$matrix = rbind(contrast$matrix[!duplicated(contrast$matrix),]) } rownames(contrast$matrix) = comp_list$dList colnames(contrast$matrix) = choices() } else if(input$def_comp == "custom_np") { wt_sum = 0 for (index in 1:length(choices())){ wt_sum = wt_sum + input[[paste0("weight", index)]] } if(wt_sum != 0){ return(contrast$matrix) } comp_list$dList = unique(c(isolate(comp_list$dList), input$comp_name)) contrast$row = matrix(row(), nrow=1) for (index in 1:length(choices())){ contrast$row[index] = input[[paste0("weight", index)]] } if (is.null(contrast$matrix)) { contrast$matrix = contrast$row } else { contrast$matrix = rbind(contrast$matrix, contrast$row) contrast$matrix = rbind(contrast$matrix[!duplicated(contrast$matrix),]) } rownames(contrast$matrix) = comp_list$dList colnames(contrast$matrix) = choices() } else if (input$def_comp == "all_one") { for (index in 1:length(choices())) { index3 = reactive({which(choices() == input$group3)}) if(index == index3()) next if(loadpage_input()$DDA_DIA=="TMT"){ comp_list$dList = c(isolate(comp_list$dList), paste(choices()[index], " vs ", input$group3, sep = "")) } else{ comp_list$dList = c(isolate(comp_list$dList), paste(choices()[index], " vs ", input$group3, sep = "")) } contrast$row = matrix(row(), nrow=1) contrast$row[index] = 1 contrast$row[index3()] = -1 if (is.null(contrast$matrix)) { contrast$matrix = contrast$row } else { contrast$matrix = rbind(contrast$matrix, contrast$row) } rownames(contrast$matrix) = comp_list$dList colnames(contrast$matrix) = choices() } } else if (input$def_comp == "all_pair") { contrast$matrix = NULL for (index in 1:length(choices())) { for (index1 in 1:length(choices())) { if (index == index1) next if (index < index1) { if(loadpage_input()$DDA_DIA=="TMT"){ comp_list$dList = c(isolate(comp_list$dList), paste(choices()[index], " vs ", choices()[index1], sep = "")) } else{ comp_list$dList = c(isolate(comp_list$dList), paste(choices()[index], " vs ", choices()[index1], sep = "")) } contrast$row = matrix(row(), nrow=1) contrast$row[index] = 1 contrast$row[index1] = -1 if (is.null(contrast$matrix)) { contrast$matrix = contrast$row } else { contrast$matrix = rbind(contrast$matrix, contrast$row) contrast$matrix = rbind(contrast$matrix[!duplicated(contrast$matrix),]) } rownames(contrast$matrix) = comp_list$dList colnames(contrast$matrix) = choices() } } } } enable("calculate") return(contrast$matrix) }) # clear matrix observeEvent({input$clear | input$clear1 | input$clear2 | input$clear3}, { disable("calculate") comp_list$dList = NULL contrast$matrix = NULL }) # Run Models data_comparison <- eventReactive(input$calculate,{ statmodel_input <- reactive({ input }) matrix = matrix_build() dataComparison(statmodel_input(),qc_input(),loadpage_input(),matrix,preprocess_data()) }) data_comparison_code = eventReactive(input$calculate, { codes = preprocessDataCode(qc_input(),loadpage_input()) comp.mat = matrix_build() codes = paste(codes, "\n# Create the contrast matrix\n", sep = "") codes = paste(codes, "contrast.matrix = NULL\n", sep = "") for(i in 1:nrow(comp.mat)){ codes = paste(codes, "comparison = matrix(c(", toString(comp.mat[i,]),"),nrow=1)\n", sep = "") codes = paste(codes, "contrast.matrix = rbind(contrast.matrix, comparison)\n", sep = "") } codes = paste(codes, "row.names(contrast.matrix)=c(\"", paste(row.names(comp.mat), collapse='","'),"\")\n", sep = "") codes = paste(codes, "colnames(contrast.matrix)=c(\"", paste(colnames(comp.mat), collapse='","'),"\")\n", sep = "") if(loadpage_input()$DDA_DIA == "TMT"){ codes = paste(codes, "\n# Model-based comparison\n", sep = "") codes = paste(codes,"model = MSstatsTMT::groupComparisonTMT(summarized, contrast.matrix = contrast.matrix, moderated = ", input$moderated,",\t\t\t\t adj.method = \"BH\", remove_norm_channel = TRUE, remove_empty_channel = TRUE )\n", sep = "") } else if (loadpage_input()$BIO == "PTM"){ if ((loadpage_input()$BIO == "PTM" & loadpage_input()$DDA_DIA == "TMT") | loadpage_input()$filetype=='phil'){ dt = "TMT" } else { dt = "LabelFree" } codes = paste(codes, "\n# Model-based comparison\n", sep = "") codes = paste(codes,"model = MSstatsPTM::groupComparisonPTM(summarized, '", dt, "', \t\t\t\t contrast.matrix = contrast.matrix)\n", sep = "") } else{ codes = paste(codes, "\n# Model-based comparison\n", sep = "") codes = paste(codes,"model = MSstats::groupComparison(contrast.matrix, summarized)\n", sep = "") } if (loadpage_input()$BIO == "PTM"){ codes = paste(codes, "groupComparisonPlotsPTM(data=model, type=\"Enter VolcanoPlot, Heatmap, or ComparisonPlot\", which.Comparison=\"all\", which.PTM=\"all\", address=\"\")\n", sep="") } else { codes = paste(codes, "groupComparisonPlots(data=model$ComparisonResult, type=\"Enter VolcanoPlot, Heatmap, or ComparisonPlot\", which.Comparison=\"all\", which.Protein=\"all\", address=\"\")\n", sep="") } return(codes) }) round_df = function(df) { nums = vapply(df, is.numeric, FUN.VALUE = logical(1)) df[,nums] = round(df[,nums], digits = 4) (df) } SignificantProteins = eventReactive(input$calculate,{ if (loadpage_input()$BIO == "PTM"){ data_comp = data_comparison() sig_unadj = data_comp$PTM.Model[ data_comp$PTM.Model$adj.pvalue < input$signif,] sig_prot = data_comp$PROTEIN.Model[ data_comp$PROTEIN.Model$adj.pvalue < input$signif,] sig_adj = data_comp$ADJUSTED.Model[ data_comp$ADJUSTED.Model$adj.pvalue < input$signif,] significant = list(PTM.Model=sig_unadj, PROTEIN.Model=sig_prot, ADJUSTED.Model=sig_adj) } else if(loadpage_input()$DDA_DIA=="TMT"){ data_comp = data_comparison() significant = data_comp$ComparisonResult[ data_comp$ComparisonResult$adj.pvalue < input$signif, ] } else { significant = with(data_comparison(), round_df(ComparisonResult[ ComparisonResult$adj.pvalue < input$signif, ])) } return(significant) }) group_comparison = function(saveFile1, pdf) { show_modal_spinner() id1 = as.character(UUIDgenerate(FALSE)) id_address1 = paste(tempdir(), "\\", id1, sep = "") path1 = function() { if (saveFile1) { path1_id = paste(tempdir(), "\\", id1, sep = "") } else { path1_id = FALSE } return(path1_id) } if (loadpage_input()$BIO=="PTM"){ plot1 = groupComparisonPlotsPTM(data_comparison(), input$typeplot, sig=input$sig, FCcutoff=input$FC, logBase.pvalue=as.integer(input$logp), ProteinName = input$pname, which.Comparison = input$whichComp, address = FALSE) } else if(loadpage_input()$DDA_DIA=="TMT"){ tryCatch({ plot1 = MSstatsShiny::groupComparisonPlots2(data=data_comparison()$ComparisonResult, type=input$typeplot, sig=input$sig, FCcutoff=input$FC, logBase.pvalue=input$logp, ProteinName=input$pname, numProtein=input$nump, clustering=input$cluster, which.Comparison=input$whichComp, which.Protein = input$whichProt, address=path1(), savePDF=pdf) remove_modal_spinner() }, error = function(e){ remove_modal_spinner() stop( '** Cannnot generate multiple plots in a screen. Please refine selection or save to a pdf. **' )} ) } else{ tryCatch({ plot1 = MSstatsShiny::groupComparisonPlots2(data=data_comparison()$ComparisonResult, type=input$typeplot, sig=input$sig, FCcutoff=input$FC, logBase.pvalue=input$logp, ProteinName=input$pname, numProtein=input$nump, clustering=input$cluster, which.Comparison=input$whichComp, which.Protein = input$whichProt, address=path1(), savePDF=pdf) }, error = function(e){ remove_modal_spinner() stop( '** Cannnot generate multiple plots in a screen. Please refine selection or save to a pdf.**' )} ) } remove_modal_spinner() if(saveFile1) { return(id_address1) } else { return(plot1) } } # model assumptions plots assumptions1 = function(saveFile3, protein) { if (input$whichProt1 != "") { id2 = as.character(UUIDgenerate(FALSE)) id_address2 = paste("tmp/",id2, sep = "") path2 = function(saveFile3) { if (saveFile3) { path_id2 = paste("www/", id_address2, sep = "") } else { path_id2 = FALSE } return (path_id2) } plots = modelBasedQCPlots(data=data_comparison(), type=input$assum_type, which.Protein = protein, address = path2()) if(saveFile3) { return(path2()) } else { return(plots) } } else { return(NULL) } } ########## output ########## # download comparison data output$compar = downloadHandler( filename = function() { paste("comparison-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data_comparison()$ComparisonResult, file) }) output$model_QC = downloadHandler( filename = function() { paste("ModelQC-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data_comparison()$ModelQC, file) }) output$fitted_v = downloadHandler( filename = function() { paste("model_summary-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(capture.output(data_comparison()$fittedmodel), file) }) # matrix output$message = renderText({ check_cond() }) observeEvent(input$calculate, {output$code.button = renderUI({ ns <- session$ns downloadButton(ns("download_code"), "Download analysis code", icon("download"), style="color: #000000; background-color: #75ba82; border-color: #000000") })}) output$matrix = renderUI({ ns <- session$ns tagList( h2("Comparison matrix"), br(), textOutput(ns("message")), br(), if (is.null(contrast$matrix)) { "" } else { dataTableOutput(ns("table")) } ) }) output$table = renderDataTable({ matrix_build() } ) # table of significant proteins output$table_results = renderUI({ ns <- session$ns req(data_comparison()) req(SignificantProteins()) if (is.null(significant)) { tagList( tags$br()) } else { tagList( tags$br(), h2("Results"), h5("There are ",textOutput(ns("number"), inline = TRUE),"significant proteins"), tags$br(), dataTableOutput(ns("significant")), downloadButton(ns("download_compar"), "Download all modeling results"), downloadButton(ns("download_signif"), "Download significant proteins") ) } }) output$adj_table_results = renderUI({ ns <- session$ns req(data_comparison()) req(SignificantProteins()) significant = SignificantProteins() if (is.null(significant$ADJUSTED.Model)) { tagList( tags$br()) } else { tagList( tags$br(), h2("Adjusted PTM Modeling Results"), h5("There are ",textOutput(ns("number_adj"), inline = TRUE),"significant PTMs"), tags$br(), dataTableOutput(ns("adj_significant")), downloadButton(ns("download_compar_adj"), "Download all modeling results"), downloadButton(ns("download_signif_adj"), "Download significant PTMs") ) } }) output$unadj_table_results = renderUI({ ns <- session$ns req(data_comparison()) req(SignificantProteins()) significant = SignificantProteins() if (is.null(significant$PTM.Model)) { tagList( tags$br()) } else { tagList( tags$br(), h2("Unadjusted PTM Modeling Results"), h5("There are ",textOutput(ns("number_unadj"), inline = TRUE),"significant PTMs"), tags$br(), dataTableOutput(ns("unadj_significant")), downloadButton(ns("download_compar_unadj"), "Download all modeling results"), downloadButton(ns("download_signif_unadj"), "Download significant PTMs") ) } }) output$prot_table_results = renderUI({ ns <- session$ns req(data_comparison()) req(SignificantProteins()) significant = SignificantProteins() if (is.null(significant$PTM.Model)) { tagList( tags$br()) } else { tagList( tags$br(), h2("Protein Modeling Results"), h5("There are ",textOutput(ns("number_prot"), inline = TRUE),"significant proteins"), tags$br(), dataTableOutput(ns("prot_significant")), downloadButton(ns("download_compar_prot"), "Download all modeling results"), downloadButton(ns("download_signif_prot"), "Download significant proteins") ) } }) output$significant = renderDataTable({ SignificantProteins() } ) output$adj_significant = renderDataTable({ SignificantProteins()$ADJUSTED.Model } ) output$unadj_significant = renderDataTable({ SignificantProteins()$PTM.Model } ) output$prot_significant = renderDataTable({ SignificantProteins()$PROTEIN.Model } ) # number of significant proteins output$number = renderText({ nrow(SignificantProteins()) }) output$number_adj = renderText({ nrow(SignificantProteins()$ADJUSTED.Model) }) output$number_unadj = renderText({ nrow(SignificantProteins()$PTM.Model) }) output$number_prot = renderText({ nrow(SignificantProteins()$PROTEIN.Model) }) # plot in browser observeEvent(input$typeplot, { updateSelectInput(session, "whichComp", selected = "all") }) observeEvent(input$viewresults, { ns <- session$ns insertUI( selector = paste0("#", ns("comparison_plots")), ui=tags$div( plotOutput(ns("comp_plots"), height = "100%", click = "click1"), conditionalPanel(condition = "input['statmodel-typeplot'] == 'VolcanoPlot' && input['loadpage-DDA_DIA']!='TMT'", h5("Click on plot for details"), verbatimTextOutput(ns("info2"))), conditionalPanel(condition = "input['statmodel-typeplot'] == 'Heatmap'", sliderInput(ns("height"), "Plot height", value = 500, min = 200, max = 1300, post = "px")) ) ) } ) observe({output$comp_plots = renderPlot({ group_comparison(FALSE, FALSE)}, height = input$height ) }) plotset = reactive({ if(loadpage_input()$DDA_DIA=="TMT"){ data_comp = data_comparison()$ComparisonResult v1 = data_comp[,1] v2 = round(data_comp[,3], 10) v3 = round(data_comp[,8], 10) v4 = data_comp[,2] } else{ v1 = data_comparison()$ComparisonResult[,1] v2 = round(data_comparison()$ComparisonResult[,3], 10) v3 = round(data_comparison()$ComparisonResult[,8], 10) v4 = data_comparison()$ComparisonResult[,2] } if (input$logp == "2") { v3 = -log2(v3) } else if (input$logp == "10") { v3 = - log10(v3) } df = data.frame(v1,v2,v3,v4) df = df[df$v4 == input$whichComp,] colnames(df) = c("Protein", "logFC", "logadj.pvalue", "comparison") return(df) }) output$info2 = renderPrint({ print(nearPoints(plotset(), input$click1, xvar = "logFC", yvar = "logadj.pvalue")) }) # Assumption plots in browser output$verify = renderUI ({ ns <- session$ns tagList( plotOutput(ns("assum_plots"), width = "800px", height = "600px"), conditionalPanel(condition = "input['statmodel-whichProt1'] != ''", actionButton(ns("saveone1"), "Save this plot"), bsTooltip(id = ns("saveone1"), title = "Open plot as pdf. Popups must be enabled", placement = "bottom", trigger = "hover"), actionButton(ns("saveall1"), "Save all plots"), bsTooltip(id = ns("saveall1"), title = "Open pdf of all plots. Popups must be enabled", placement = "bottom", trigger = "hover") ) ) }) output$assum_plots = renderPlot({ assumptions1(FALSE, input$whichProt1)}) # downloads observeEvent(input$saveone1, { path = assumptions1(TRUE, input$whichProt1) if (input$assum_type == "QQPlots") { js = paste("window.open('", path, "QQPlot.pdf')", sep="") runjs(js); } else if (input$type == "ResidualPlots") { js = paste("window.open('", path, "ResidualPlots.pdf')", sep="") runjs(js); } }) observeEvent(input$saveall1, { path = assumptions1(TRUE, "all") if (input$assum_type == "QQPlots") { js = paste("window.open('", path, "QQPlot.pdf')", sep="") runjs(js); } else if (input$type == "ResidualPlots") { js = paste("window.open('", path, "ResidualPlots.pdf')", sep="") runjs(js); } }) output$download_compar = downloadHandler( filename = function() { paste("test_result-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data_comparison()$ComparisonResult, file) } ) output$download_compar_adj = downloadHandler( filename = function() { paste("adj_data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data_comparison()$ADJUSTED.Model, file) } ) output$download_compar_unadj = downloadHandler( filename = function() { paste("unadj_data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data_comparison()$PTM.Model, file) } ) output$download_compar_prot = downloadHandler( filename = function() { paste("prot_data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(data_comparison()$PROTEIN.Model, file) } ) output$download_code = downloadHandler( filename = function() { paste("mstats-code-", Sys.Date(), ".R", sep="") }, content = function(file) { writeLines(paste( data_comparison_code(), sep = ""), file) }) output$download_signif = downloadHandler( filename = function() { paste("data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(SignificantProteins(), file) } ) output$download_signif_adj = downloadHandler( filename = function() { paste("adj_data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(SignificantProteins()$ADJUSTED.Model, file) } ) output$download_signif_unadj = downloadHandler( filename = function() { paste("unadj_data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(SignificantProteins()$PTM.Model, file) } ) output$download_signif_prot = downloadHandler( filename = function() { paste("prot_data-", Sys.Date(), ".csv", sep="") }, content = function(file) { write.csv(SignificantProteins()$PROTEIN.Model, file) } ) output$plotresults = downloadHandler( filename = function() { paste("SummaryPlot-", Sys.Date(), ".pdf", sep="") }, content = function(file) { pdf(file) group_comparison(TRUE, TRUE) dev.off() } ) observeEvent(input$calculate,{ enable("Design") enable("typeplot") enable("WhichComp") enable("download_code") }) return( list( input = input, dataComparison = data_comparison ) ) }