|
2 | 2 | #' |
3 | 3 | #' Operates on the column names produced by MZMine after MSstatsConvert's |
4 | 4 | #' internal column-name standardization (spaces collapsed and dots removed): |
5 | | -#' "row ID" becomes `rowID`, "row m/z" becomes `rowmz`, "row retention time" |
6 | | -#' becomes `rowretentiontime`, and each "<sample> Peak area" becomes |
| 5 | +#' "row ID" becomes `rowID`, and each "<sample> Peak area" becomes |
7 | 6 | #' `<standardized-sample>Peakarea`. |
8 | 7 | #' |
9 | 8 | #' @param msstats_object an object of class `MSstatsMZMineFiles`. |
10 | | -#' @param mzmine_annotations optional `data.frame` of MZMine spectral-library |
11 | | -#' annotations with columns `id`, `compound_name`, `score`. When supplied, |
12 | | -#' the highest-scoring `compound_name` per feature is used as `ProteinName`. |
13 | | -#' Features without a matching annotation row fall back to an mz_rt string |
14 | | -#' `paste0(round(mz, 4), "_", round(rt, 2))`. When `NULL`, every feature |
15 | | -#' uses the mz_rt fallback. |
| 9 | +#' @param mzmine_annotations `data.frame` of MZMine spectral-library |
| 10 | +#' annotations with columns `id`, `compound_name`, `score`. Required; |
| 11 | +#' passing `NULL` raises an error. The highest-scoring `compound_name` |
| 12 | +#' per feature is used as `ProteinName`, and features in the quant |
| 13 | +#' table with no matching annotation row are dropped from the output. |
| 14 | +#' These are MSI Level 2 annotations (putative identification via |
| 15 | +#' MS/MS spectral matching). See the public `MZMinetoMSstatsFormat` |
| 16 | +#' docstring for the full scope discussion. |
16 | 17 | #' @return data.table |
17 | 18 | #' @keywords internal |
18 | | -.cleanRawMZMine <- function(msstats_object, mzmine_annotations = NULL) { |
| 19 | +.cleanRawMZMine <- function(msstats_object, mzmine_annotations) { |
19 | 20 | ProteinName = PeptideSequence = Intensity = Run = NULL |
20 | 21 | PrecursorCharge = FragmentIon = ProductCharge = NULL |
21 | 22 | id = score = compound_name = i.compound_name = NULL |
|
31 | 32 | "columns named '<run> Peak area' (e.g. 'sampleA.mzML Peak area').") |
32 | 33 | } |
33 | 34 | id_col <- "rowID" |
34 | | - mz_col <- "rowmz" |
35 | | - rt_col <- "rowretentiontime" |
36 | | - required_meta <- c(id_col, mz_col, rt_col) |
| 35 | + required_meta <- id_col |
37 | 36 | missing_meta <- setdiff(required_meta, colnames(mz_input)) |
38 | 37 | if (length(missing_meta) > 0) { |
39 | | - stop("Missing required MZMine metadata column(s) (expected 'row ID', ", |
40 | | - "'row m/z', 'row retention time'). After standardization, ", |
41 | | - "looked for: ", paste(missing_meta, collapse = ", "), ".") |
| 38 | + stop("Missing required MZMine metadata column (expected 'row ID'). ", |
| 39 | + "After standardization, looked for: ", |
| 40 | + paste(missing_meta, collapse = ", "), ".") |
42 | 41 | } |
43 | 42 |
|
44 | | - mz_rt_fallback <- paste0(round(mz_input[[mz_col]], 4), "_", |
45 | | - round(mz_input[[rt_col]], 2)) |
46 | | - mz_input[, ProteinName := mz_rt_fallback] |
47 | | - |
48 | | - if (!is.null(mzmine_annotations)) { |
49 | | - feature_to_compound <- data.table::as.data.table(mzmine_annotations) |
50 | | - required_ann <- c("id", "compound_name", "score") |
51 | | - missing_ann <- setdiff(required_ann, colnames(feature_to_compound)) |
52 | | - if (length(missing_ann) > 0) { |
53 | | - stop("mzmine_annotations is missing required column(s): ", |
54 | | - paste(missing_ann, collapse = ", "), ".") |
55 | | - } |
56 | | - feature_to_compound[, score := suppressWarnings(as.numeric(score))] |
57 | | - if (anyNA(feature_to_compound$score)) { |
58 | | - stop("The 'score' column in the mzmine annotations file must contain numeric values.") |
59 | | - } |
60 | | - # Sort by id ascending and score descending so the highest-scoring |
61 | | - # annotation per id is the first row in each group. |
62 | | - data.table::setorder(feature_to_compound, id, -score) |
63 | | - # Collapse to one row per id (the highest-scoring). data.table's |
64 | | - # unique() with a 'by' arg keeps the first row per group, which after |
65 | | - # the sort above is the highest-scoring annotation. |
66 | | - feature_to_compound <- unique(feature_to_compound, by = "id") |
67 | | - # Join: unmatched mz_input rows keep the mz_rt_fallback ProteinName |
68 | | - # set above. |
69 | | - mz_input[ |
70 | | - feature_to_compound, |
71 | | - ProteinName := i.compound_name, |
72 | | - on = setNames("id", id_col) |
73 | | - ] |
| 43 | + if (is.null(mzmine_annotations)) { |
| 44 | + stop("mzmine_annotations is required. Pass a data.frame with ", |
| 45 | + "columns 'id', 'compound_name', 'score'.") |
| 46 | + } |
| 47 | + feature_to_compound <- data.table::as.data.table(mzmine_annotations) |
| 48 | + required_ann <- c("id", "compound_name", "score") |
| 49 | + missing_ann <- setdiff(required_ann, colnames(feature_to_compound)) |
| 50 | + if (length(missing_ann) > 0) { |
| 51 | + stop("mzmine_annotations is missing required column(s): ", |
| 52 | + paste(missing_ann, collapse = ", "), ".") |
74 | 53 | } |
| 54 | + feature_to_compound[, score := suppressWarnings(as.numeric(score))] |
| 55 | + if (anyNA(feature_to_compound$score)) { |
| 56 | + stop("The 'score' column in the mzmine annotations file must contain numeric values.") |
| 57 | + } |
| 58 | + data.table::setorder(feature_to_compound, id, -score) |
| 59 | + feature_to_compound <- unique(feature_to_compound, by = "id") |
| 60 | + # Inner-join filter: drop quant rows with no matching annotation. |
| 61 | + mz_input[ |
| 62 | + feature_to_compound, |
| 63 | + ProteinName := i.compound_name, |
| 64 | + on = setNames("id", id_col) |
| 65 | + ] |
| 66 | + mz_input <- mz_input[!is.na(ProteinName)] |
| 67 | + |
| 68 | + retained_ids <- feature_to_compound$id |
| 69 | + retained_msg <- paste0("** MZMine: retained ", length(retained_ids), |
| 70 | + " feature(s) after annotation join: ", |
| 71 | + paste(retained_ids, collapse = ", ")) |
| 72 | + getOption("MSstatsLog")("INFO", retained_msg) |
| 73 | + getOption("MSstatsMsg")("INFO", retained_msg) |
75 | 74 |
|
76 | 75 | mz_input[, PeptideSequence := as.character(get(id_col))] |
77 | 76 |
|
|
0 commit comments