Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions R/module-loadpage-server.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ loadpageServer <- function(id, parent_session, is_web_server = FALSE) {
})

# Render just the filename for user feedback in the UI.
output$specdata_big_path <- renderPrint({
output$big_file_path <- renderPrint({
req(nrow(local_file_info()) > 0)
cat(local_file_info()$name)
})
Expand Down Expand Up @@ -72,6 +72,52 @@ loadpageServer <- function(id, parent_session, is_web_server = FALSE) {
tagList(ui_elements, create_separator_buttons(session$ns, "sep_specdata"))
})

output$diann_header_ui <- renderUI({
req(input$filetype == 'diann', input$BIO != 'PTM')
create_diann_header()
})

output$diann_file_selection_ui <- renderUI({
req(input$filetype == 'diann', input$BIO != 'PTM')

ui_elements <- tagList()

if (!is_web_server) {
ui_elements <- tagList(ui_elements, create_diann_mode_selector(session$ns, isTRUE(input$big_file_diann)))

if (isTRUE(input$big_file_diann)) {
ui_elements <- tagList(ui_elements, create_diann_large_file_ui(session$ns))
} else {
ui_elements <- tagList(ui_elements, create_diann_standard_ui(session$ns))
}
} else {
ui_elements <- tagList(ui_elements, create_diann_standard_ui(session$ns))
}

tagList(ui_elements, create_separator_buttons(session$ns, "sep_dianndata"))
})
Comment thread
coderabbitai[bot] marked this conversation as resolved.

output$diann_options_ui <- renderUI({
req(input$filetype == 'diann', input$BIO != 'PTM')

if (!is_web_server && isTRUE(input$big_file_diann)) {
mbr_def <- if (is.null(input$diann_MBR)) TRUE else input$diann_MBR
quant_col_def <- if (is.null(input$diann_quantificationColumn)) "Fragment.Quant.Corrected" else input$diann_quantificationColumn

max_feature_def <- if (is.null(input$max_feature_count)) 100 else input$max_feature_count
unique_peps_def <- if (is.null(input$filter_unique_peptides)) FALSE else input$filter_unique_peptides
agg_psms_def <- if (is.null(input$aggregate_psms)) FALSE else input$aggregate_psms
few_obs_def <- if (is.null(input$filter_few_obs)) FALSE else input$filter_few_obs

tagList(
create_diann_large_filter_options(session$ns, mbr_def, quant_col_def),
create_diann_large_bottom_ui(session$ns, max_feature_def, unique_peps_def, agg_psms_def, few_obs_def)
)
} else {
NULL
}
})

output$spectronaut_options_ui <- renderUI({
req(input$filetype == 'spec', input$BIO != 'PTM')

Expand Down Expand Up @@ -195,7 +241,9 @@ loadpageServer <- function(id, parent_session, is_web_server = FALSE) {
enable("proceed1")
}
} else if (input$filetype == "diann") {
if(!is.null(input$dianndata) && !is.null(input$sep_dianndata)) { # && !is.null(input$annot)
diann_regular_file_ok <- !isTRUE(input$big_file_diann) && !is.null(input$dianndata)
diann_big_file_ok <- isTRUE(input$big_file_diann) && length(local_big_file_path()) > 0
if((diann_regular_file_ok || diann_big_file_ok) && !is.null(input$sep_dianndata)) {
enable("proceed1")
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Expand Down
60 changes: 54 additions & 6 deletions R/module-loadpage-ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,10 @@ create_skyline_uploads <- function(ns) {
#' Create DIANN file uploads
#' @noRd
create_diann_uploads <- function(ns) {
conditionalPanel(
condition = "input['loadpage-filetype'] == 'diann' && input['loadpage-BIO'] != 'PTM'",
h4("4. Upload MSstats report from DIANN"),
fileInput(ns('dianndata'), "", multiple = FALSE, accept = NULL),
create_separator_buttons(ns, "sep_dianndata")
tagList(
uiOutput(ns("diann_header_ui")),
uiOutput(ns("diann_file_selection_ui")),
uiOutput(ns("diann_options_ui"))
Comment thread
tonywu1999 marked this conversation as resolved.
)
}

Expand All @@ -295,24 +294,51 @@ create_spectronaut_header <- function() {
h4("4. Upload MSstats scheme output from Spectronaut")
}

#' Create DIANN header
#' @noRd
create_diann_header <- function() {
h4("4. Upload MSstats report from DIANN")
}

#' Create Spectronaut mode selector (Local only)
#' @noRd
create_spectronaut_mode_selector <- function(ns, selected = FALSE) {
checkboxInput(ns("big_file_spec"), "Large file mode", value = selected)
}

#' Create DIANN mode selector (Local only)
#' @noRd
create_diann_mode_selector <- function(ns, selected = FALSE) {
checkboxInput(ns("big_file_diann"), "Large file mode", value = selected)
}

#' Create Spectronaut standard file input
#' @noRd
create_spectronaut_standard_ui <- function(ns) {
fileInput(ns('specdata'), "", multiple = FALSE, accept = NULL)
}

#' Create DIANN standard file input
#' @noRd
create_diann_standard_ui <- function(ns) {
fileInput(ns('dianndata'), "", multiple = FALSE, accept = NULL)
}

#' Create Spectronaut large file selection UI
#' @noRd
create_spectronaut_large_file_ui <- function(ns) {
tagList(
shinyFiles::shinyFilesButton(ns("big_file_browse"), "Browse for local file...", "Please select a file", multiple = FALSE),
verbatimTextOutput(ns("specdata_big_path"))
verbatimTextOutput(ns("big_file_path"))
)
}

#' Create DIANN large file selection UI
#' @noRd
create_diann_large_file_ui <- function(ns) {
tagList(
shinyFiles::shinyFilesButton(ns("big_file_browse"), "Browse for local file...", "Please select a file", multiple = FALSE),
verbatimTextOutput(ns("big_file_path"))
)
}

Expand All @@ -328,6 +354,17 @@ create_spectronaut_large_filter_options <- function(ns, excluded_def = FALSE, id
)
}

#' Create DIANN large file filter options
#' @noRd
create_diann_large_filter_options <- function(ns, mbr_def = TRUE, quant_col_def = "Fragment.Quant.Corrected") {
tagList(
tags$hr(),
h4("Options for large file processing"),
checkboxInput(ns("diann_MBR"), "MBR Enabled", value = mbr_def),
textInput(ns("diann_quantificationColumn"), "Quantification Column", value = quant_col_def)
)
}

#' Create Spectronaut Q-value cutoff input
#' @noRd
create_spectronaut_qvalue_cutoff_ui <- function(ns, cutoff_def = 0.01) {
Expand All @@ -345,6 +382,17 @@ create_spectronaut_large_bottom_ui <- function(ns, max_feature_def = 20, unique_
)
}

#' Create DIANN large file options (Bottom part)
#' @noRd
create_diann_large_bottom_ui <- function(ns, max_feature_def = 100, unique_peps_def = FALSE, agg_psms_def = FALSE, few_obs_def = FALSE) {
tagList(
numericInput(ns("max_feature_count"), "Max feature count", value = max_feature_def, min = 1),
checkboxInput(ns("filter_unique_peptides"), "Use unique peptides", value = unique_peps_def),
checkboxInput(ns("aggregate_psms"), "Aggregate PSMs to peptides", value = agg_psms_def),
checkboxInput(ns("filter_few_obs"), "Filter features with few observations", value = few_obs_def)
)
}

#' Create PTM FragPipe uploads
#' @noRd
create_ptm_fragpipe_uploads <- function(ns) {
Expand Down
142 changes: 122 additions & 20 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,69 @@ getData <- function(input) {
}
}
else if(input$filetype == 'diann') {
if (isTRUE(input$big_file_diann)) {
# Logic for big DIANN files
# Parse the file path from shinyFiles input
volumes <- shinyFiles::getVolumes()()
path_info <- shinyFiles::parseFilePaths(volumes, input$big_file_browse)
local_big_file_path <- if (nrow(path_info) > 0) path_info$datapath else NULL

if (!is.numeric(input$max_feature_count) || is.na(input$max_feature_count) || input$max_feature_count <= 0) {
showNotification("Error: max_feature_count must be a positive number.", type = "error")
shinybusy::remove_modal_spinner()
return(NULL)
}

if (is.null(local_big_file_path) || !file.exists(local_big_file_path)) {
showNotification("Error: The selected file does not exist or is not readable.", type = "error")
shinybusy::remove_modal_spinner()
return(NULL)
}

shinybusy::update_modal_spinner(text = "Processing large DIANN file...")

# Call the big file conversion function from MSstatsConvert
converted_data <- MSstatsBig::bigDIANNtoMSstatsFormat(
input_file = local_big_file_path,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

  1. The annotation file will need to be incorporated into this function
  2. Add bigDIANNtoMSstatsFormat and bigSpectronauttoMSstatsFormat as dependencies in this file. And then you won't need to do MSstatsBig:: when calling the function.

output_file_name = "output_file.csv",
backend = "arrow",
MBR = isTRUE(input$diann_MBR),
quantificationColumn = input$diann_quantificationColumn,
max_feature_count = input$max_feature_count,
filter_unique_peptides = input$filter_unique_peptides,
aggregate_psms = input$aggregate_psms,
filter_few_obs = input$filter_few_obs
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same hardcoded output file name issue as Spectronaut path.

The output_file_name = "output_file.csv" is also hardcoded here. Apply the same fix using tempfile() for consistency and to avoid file collisions.

🛠️ Suggested fix
         converted_data <- MSstatsBig::bigDIANNtoMSstatsFormat(
           input_file = local_big_file_path,
-          output_file_name = "output_file.csv",
+          output_file_name = tempfile(pattern = "diann_", fileext = ".csv"),
           backend = "arrow",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
converted_data <- MSstatsBig::bigDIANNtoMSstatsFormat(
input_file = local_big_file_path,
output_file_name = "output_file.csv",
backend = "arrow",
MBR = isTRUE(input$diann_MBR),
quantificationColumn = input$diann_quantificationColumn,
max_feature_count = input$max_feature_count,
filter_unique_peptides = input$filter_unique_peptides,
aggregate_psms = input$aggregate_psms,
filter_few_obs = input$filter_few_obs
)
converted_data <- MSstatsBig::bigDIANNtoMSstatsFormat(
input_file = local_big_file_path,
output_file_name = tempfile(pattern = "diann_", fileext = ".csv"),
backend = "arrow",
MBR = isTRUE(input$diann_MBR),
quantificationColumn = input$diann_quantificationColumn,
max_feature_count = input$max_feature_count,
filter_unique_peptides = input$filter_unique_peptides,
aggregate_psms = input$aggregate_psms,
filter_few_obs = input$filter_few_obs
)
🤖 Prompt for AI Agents
In `@R/utils.R` around lines 617 - 627, The call to
MSstatsBig::bigDIANNtoMSstatsFormat uses a hardcoded output_file_name
("output_file.csv"); replace that literal with a unique temporary filename (e.g.
generate via tempfile() with an appropriate file extension) and pass that
variable as output_file_name in the converted_data assignment so the function
uses a temp file for local_big_file_path conversion; ensure the tempfile is
created before the call and removed/managed after use to avoid collisions.


# Attempt to load the data into memory.
mydata <- tryCatch({
dplyr::collect(converted_data)
}, error = function(e) {
showNotification(
paste("Memory Error: The dataset is too large to process in-memory.", e$message),
type = "error",
duration = NULL
)
return(NULL)
})

if (is.null(mydata)) {
shinybusy::remove_modal_spinner()
return(NULL)
}
Comment on lines +595 to +645
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n 'big_file_browse' --type=r -C2

Repository: Vitek-Lab/MSstatsShiny

Length of output: 2953


🏁 Script executed:

rg -n 'bigDIANNtoMSstatsFormat' --type=r -C5

Repository: Vitek-Lab/MSstatsShiny

Length of output: 4398


🏁 Script executed:

sed -n '938,955p' R/utils.R

Repository: Vitek-Lab/MSstatsShiny

Length of output: 1306


🏁 Script executed:

# Check if both Spectronaut and DIANN big file UIs are conditionally rendered or always active
rg -n 'create_spectronaut_large_file_ui|create_diann_large_file_ui' -C3

Repository: Vitek-Lab/MSstatsShiny

Length of output: 2795


Generated code for DIANN big-file conversion is missing the annotation parameter.

The runtime code at line 619 correctly includes annotation = getAnnot(input) in the bigDIANNtoMSstatsFormat() call. However, the generated code (lines 938–955 in the getDataCode function) omits this parameter. The generated code should include:

codes = paste(codes, "  annotation = \"insert your annotation file path\",\n", sep = "")

The shared input$big_file_browse input ID is appropriate—both Spectronaut and DIANN large-file UIs are conditionally rendered (only one active at a time based on input$big_file_spec or input$big_file_diann), so the single shinyFileChoose binding works correctly.

🤖 Prompt for AI Agents
In `@R/utils.R` around lines 595 - 645, The generated code in getDataCode omits
the annotation argument when emitting the bigDIANNtoMSstatsFormat() call; update
getDataCode to include a line that appends the annotation parameter (e.g., codes
= paste(codes, "  annotation = \"insert your annotation file path\",\\n", sep =
"")) so the generated call matches the runtime call (bigDIANNtoMSstatsFormat
with annotation = getAnnot(input)); ensure the string is properly escaped and
includes the trailing comma/newline and references input$big_file_browse/shared
UI as before.

} else {
if (getFileExtension(input$dianndata$name) %in% c("parquet", "pq")) {
data = read_parquet(input$dianndata$datapath)
} else {
data = read.csv(input$dianndata$datapath, sep=input$sep_dianndata)
sep = input$sep_dianndata
if(is.null(sep)) {
sep = "\t"
}
if (sep == "\t") {
data = read.delim(input$dianndata$datapath)
} else {
data = read.csv(input$dianndata$datapath, sep = sep)
}
}

qvalue_cutoff = 0.01
Expand All @@ -620,6 +679,7 @@ getData <- function(input) {
use_log_file = FALSE,
quantificationColumn = quantificationColumn
)
}
print("Mydata from mstats")
print(mydata)
}
Expand Down Expand Up @@ -721,7 +781,8 @@ library(MSstatsTMT)
library(MSstatsPTM)\n", sep = "")
codes = paste(codes, "\n# Package versions\n# MSstats version ", packageVersion("MSstats"),
"\n# MSstatsTMT version ", packageVersion("MSstatsTMT"),
"\n# MSstatsPTM version ", packageVersion("MSstatsPTM"), sep = "")
"\n# MSstatsPTM version ", packageVersion("MSstatsPTM"),
"\n# MSstatsBig version ", tryCatch(packageVersion("MSstatsBig"), error = function(e) "Not Installed"), sep = "")
codes = paste(codes, "\n\n# Read data\n", sep = "")
if(input$filetype == 'sample') {
if(input$BIO != "PTM" && input$DDA_DIA =='LType' && input$LabelFreeType == "SRM_PRM") {
Expand Down Expand Up @@ -843,27 +904,68 @@ library(MSstatsPTM)\n", sep = "")
}
else if(input$filetype == 'spec') {

codes = paste(codes, "data = read.csv(\"insert your MSstats scheme output from Spectronaut filepath\", header = TRUE, sep = ",input$sep_specdata,")\nannot_file = read.csv(\"insert your annotation filepath\", sep='\t')#Optional\n"
, sep = "")

codes = paste(codes, "data = SpectronauttoMSstatsFormat(data,
annotation = annot_file #Optional,
filter_with_Qvalue = TRUE, ## same as default
qvalue_cutoff = 0.01, ## same as default
fewMeasurements=\"remove\",
removeProtein_with1Feature = TRUE,
use_log_file = FALSE)\n", sep = "")
if (isTRUE(input$big_file_spec)) {
codes = paste(codes, "library(MSstatsBig)\n", sep = "")
codes = paste(codes, "data = MSstatsBig::bigSpectronauttoMSstatsFormat(\n", sep = "")
codes = paste(codes, " input_file = \"insert your large Spectronaut file path\",\n", sep = "")
codes = paste(codes, " output_file_name = \"output_file.csv\",\n", sep = "")
codes = paste(codes, " backend = \"arrow\",\n", sep = "")
codes = paste(codes, " filter_by_excluded = ", input$filter_by_excluded, ",\n", sep = "")
codes = paste(codes, " filter_by_identified = ", input$filter_by_identified, ",\n", sep = "")
codes = paste(codes, " filter_by_qvalue = ", input$filter_by_qvalue, ",\n", sep = "")
codes = paste(codes, " qvalue_cutoff = ", input$qvalue_cutoff, ",\n", sep = "")
codes = paste(codes, " max_feature_count = ", input$max_feature_count, ",\n", sep = "")
codes = paste(codes, " filter_unique_peptides = ", input$filter_unique_peptides, ",\n", sep = "")
codes = paste(codes, " aggregate_psms = ", input$aggregate_psms, ",\n", sep = "")
codes = paste(codes, " filter_few_obs = ", input$filter_few_obs, "\n", sep = "")
codes = paste(codes, ")\n", sep = "")
codes = paste(codes, "data = dplyr::collect(data)\n", sep = "")
} else {
codes = paste(codes, "data = read.csv(\"insert your MSstats scheme output from Spectronaut filepath\", header = TRUE, sep = ",input$sep_specdata,")\nannot_file = read.csv(\"insert your annotation filepath\", sep='\t')#Optional\n"
, sep = "")
codes = paste(codes, "data = SpectronauttoMSstatsFormat(data,
annotation = annot_file #Optional,
filter_with_Qvalue = TRUE, ## same as default
qvalue_cutoff = 0.01, ## same as default
fewMeasurements=\"remove\",
removeProtein_with1Feature = TRUE,
use_log_file = FALSE)\n", sep = "")
}
}
else if(input$filetype == 'diann') {

codes = paste(codes, "data = read.csv(\"insert your MSstats scheme output from DIANN filepath\", header = TRUE, sep = '\\t')\nannot_file = read.csv(\"insert your annotation filepath\")#Optional\n"
, sep = "")

codes = paste(codes, "data = DIANNtoMSstatsFormat(data,
annotation = annot_file, #Optional
qvalue_cutoff = 0.01, ## same as default
removeProtein_with1Feature = TRUE,
use_log_file = FALSE)\n", sep = "")
if (isTRUE(input$big_file_diann)) {
codes = paste(codes, "library(MSstatsBig)\n", sep = "")
codes = paste(codes, "data = MSstatsBig::bigDIANNtoMSstatsFormat(\n", sep = "")
codes = paste(codes, " input_file = \"insert your large DIANN file path\",\n", sep = "")
codes = paste(codes, " output_file_name = \"output_file.csv\",\n", sep = "")
codes = paste(codes, " backend = \"arrow\",\n", sep = "")
codes = paste(codes, " MBR = ", isTRUE(input$diann_MBR), ",\n", sep = "")
codes = paste(codes, " quantificationColumn = \"", input$diann_quantificationColumn, "\",\n", sep = "")
codes = paste(codes, " max_feature_count = ", input$max_feature_count, ",\n", sep = "")
codes = paste(codes, " filter_unique_peptides = ", input$filter_unique_peptides, ",\n", sep = "")
codes = paste(codes, " aggregate_psms = ", input$aggregate_psms, ",\n", sep = "")
codes = paste(codes, " filter_few_obs = ", input$filter_few_obs, "\n", sep = "")
codes = paste(codes, ")\n", sep = "")
codes = paste(codes, "data = dplyr::collect(data)\n", sep = "")
Comment on lines +938 to +951
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Generated code for big DIANN is missing the annotation parameter.

The runtime call at line 619 passes annotation = getAnnot(input), but the code snippet emitted here omits it. Users attempting to reproduce the analysis with the generated code will get incorrect results or an error if annotation is required.

Proposed fix
         codes = paste(codes, "data = MSstatsBig::bigDIANNtoMSstatsFormat(\n", sep = "")
         codes = paste(codes, "  input_file = \"insert your large DIANN file path\",\n", sep = "")
+        codes = paste(codes, "  annotation = read.csv(\"insert your annotation filepath\"),\n", sep = "")
         codes = paste(codes, "  output_file_name = \"output_file.csv\",\n", sep = "")
🤖 Prompt for AI Agents
In `@R/utils.R` around lines 938 - 951, The generated big DIANN code omits the
annotation argument for MSstatsBig::bigDIANNtoMSstatsFormat; update the code
building block that constructs the bigDIANN call (where codes is appended with
"data = MSstatsBig::bigDIANNtoMSstatsFormat(") to include annotation =
getAnnot(input) as a parameter (matching how the runtime uses annotation =
getAnnot(input)), ensuring proper comma placement and quoting/concatenation
consistent with the surrounding parameters (e.g., alongside input_file, backend,
MBR, quantificationColumn, etc.) so the emitted call contains annotation =
getAnnot(input).

} else {
sep = input$sep_dianndata
if(is.null(sep)) {
sep = "\t"
}

if (sep == "\t") {
codes = paste(codes, "data = read.delim(\"insert your MSstats scheme output from DIANN filepath\")\nannot_file = read.csv(\"insert your annotation filepath\")#Optional\n", sep = "")
} else {
codes = paste(codes, "data = read.csv(\"insert your MSstats scheme output from DIANN filepath\", header = TRUE, sep = '", sep, "')\nannot_file = read.csv(\"insert your annotation filepath\")#Optional\n", sep = "")
}

codes = paste(codes, "data = DIANNtoMSstatsFormat(data,
annotation = annot_file, #Optional
qvalue_cutoff = 0.01, ## same as default
removeProtein_with1Feature = TRUE,
use_log_file = FALSE)\n", sep = "")
}
}
else if(input$filetype == 'open') {

Expand Down
Loading
Loading