From f889296c2ed219867d52e77cdff77adfe00e0a97 Mon Sep 17 00:00:00 2001 From: jotsetung Date: Wed, 7 Nov 2018 08:45:04 +0100 Subject: [PATCH] Add filterMsLevel,Spectra and coerce,Spectra,MSnExp - Add filterMsLevel,Spectra method. - Add coerce,Spectra,MSnExp method (issue #370). - Add related unit tests and documentation. --- NEWS | 1 + NEWS.md | 1 + R/DataClasses.R | 20 ++++---- R/methods-Spectra.R | 55 +++++++++++++++++---- man/Spectra.Rd | 12 +++-- tests/testthat/test_methods-Spectra.R | 70 +++++++++++++++++++++++---- 6 files changed, 127 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index e010215fe..bcc9b7601 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Changes in version 2.9.1 - Add clean,Chromatograms (issue #354) <2018-11-07 Wed> - Add as,Spectra,list as,Spectra,MSnExp and as,MSnExp,Spectra (issue #370) <2018-11-07 Wed> +- Add filterMsLevel,Spectra <2018-11-07 Wed> Changes in version 2.9.0 - New version for Bioc 3.9 devel diff --git a/NEWS.md b/NEWS.md index 7577e1a1f..848926558 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ [#354](https://github.com/lgatto/MSnbase/issues/354)) <2018-11-07 Wed> - Add as,Spectra,list as,Spectra,MSnExp and as,MSnExp,Spectra (issue [#370](https://github.com/lgatto/MSnbase/issues/370)) <2018-11-07 Wed> +- Add filterMsLevel,Spectra <2018-11-07 Wed> ## Changes in version 2.9.0 - New version for Bioc 3.9 devel diff --git a/R/DataClasses.R b/R/DataClasses.R index e32af7818..f76bcb06f 100644 --- a/R/DataClasses.R +++ b/R/DataClasses.R @@ -523,9 +523,9 @@ setClass("ProcessingStep", #' example, a \code{Chromatogram} for a SRM transition 273 -> 153 will have #' a \code{@precursorMz = c(273, 273)} and a #' \code{@productMz = c(153, 153)}. -#' +#' #' @rdname Chromatogram-class -#' +#' #' @export #' #' @seealso \code{\link{Chromatograms}} for combining \code{Chromatogram} in @@ -535,7 +535,7 @@ setClass("ProcessingStep", #' object. #' \code{\link{clean}} for the method to \emph{clean} a \code{Chromatogram} #' object. -#' +#' #' @author Johannes Rainer #' #' @examples @@ -588,7 +588,7 @@ setClass("Chromatogram", #' @title Container for multiple Chromatogram objects #' #' @aliases coerce,matrix,Chromatograms-method -#' +#' #' @description The \code{Chromatograms} class allows to store #' \code{\link{Chromatogram}} objects in a \code{matrix}-like #' two-dimensional structure. @@ -611,9 +611,9 @@ setClass("Chromatogram", #' \code{\linkS4class{OnDiskMSnExp}} object. #' \code{\link{readSRMData}} for the function to read chromatographic data #' of an SRM/MRM experiment. -#' +#' #' @author Johannes Rainer -#' +#' #' @examples #' ## Creating some chromatogram objects to put them into a Chromatograms object #' ints <- abs(rnorm(25, sd = 200)) @@ -676,8 +676,8 @@ setClass("Chromatograms", #' @name Spectra #' -#' @aliases Spectra-class show,Spectra-method coerce,Spectra,list-method -#' +#' @aliases Spectra-class show,Spectra-method coerce,Spectra,list-method coerce,Spectra,MSnExp-method +#' #' @title List of Spectrum objects along with annotations #' #' @description @@ -688,7 +688,7 @@ setClass("Chromatograms", #' `Spectrum` object. These can be accessed/set with the [mcols()] method. #' #' `Spectra` objects can be created with the `Spectra` function. -#' +#' #' Functions to access the individual spectra's attributes are available #' (listed below). #' @@ -701,7 +701,7 @@ setClass("Chromatograms", #' @param object For all functions: a `Spectra` object. #' #' @param x For all functions: a `Spectra` object. -#' +#' #' @md #' #' @rdname Spectra diff --git a/R/methods-Spectra.R b/R/methods-Spectra.R index dc6b3b57f..f2a442cbe 100644 --- a/R/methods-Spectra.R +++ b/R/methods-Spectra.R @@ -61,9 +61,6 @@ setMethod("show", "Spectra", function(object) { #' #' - `clean` *cleans* each spectrum. See [clean()] for more details. #' -#' - `filterMz` filters the spectra by the specified `mz` range. See -#' [filterMz()] for details. -#' #' - `pickPeaks` performs peak picking to generate centroided spectra. See #' [pickPeaks()] for more details. #' @@ -72,6 +69,17 @@ setMethod("show", "Spectra", function(object) { #' #' - `smooth` *smooths* spectra. See [smooth()] for more details. #' +#' @section Filtering and subsetting +#' +#' - `[` can be used to subset the `Spectra` object. +#' +#' - `filterMsLevel` filters `Spectra` to retain only spectra from certain MS +#' level(s). +#' +#' - `filterMz` filters the spectra by the specified `mz` range. See +#' [filterMz()] for details. +#' +#' #' @md #' #' @param all For `clean`: if `FALSE` original 0-intensity values are retained @@ -79,6 +87,7 @@ setMethod("show", "Spectra", function(object) { #' #' @param msLevel. For `clean`, `removePeaks`, `filterMz`: optionally specify #' the MS level of the spectra on which the operation should be performed. +#' For `filterMsLevels`: MS level(s) to which the `Spectra` should be reduced. #' #' @param method For `pickPeaks` and `smooth`: see [pickPeaks()] and [smooth()] #' for details. @@ -518,12 +527,40 @@ setAs("Spectra", "list", function(from) { from@listData }) -## setAs("Spectra", "MSnExp", function(from) { -## ## mcols -> featureData -## ## empty phenoData -## ## empty processing -## ## spectra -> spectra -## }) +setAs("Spectra", "MSnExp", function(from) { + if (length(unique(msLevel(from))) > 1) + stop("'from' contains Spectra from more than one MS level. Use ", + "'filterMsLevel' to restrict to Spectra from a single MS level ", + "before coercing.") + if (!length(names(from))) + names(from) <- as.character(seq_len(length(from))) + if (is.null(mcols(from))) + fd <- AnnotatedDataFrame(data.frame(spectrum = seq_len(length(from)), + row.names = names(from))) + else + fd <- AnnotatedDataFrame(as.data.frame(mcols(from))) + fromf <- as.character(unique(fromFile(from))) + process <- new("MSnProcess", files = fromf, + processing = paste("Data converted from Spectra:", date())) + pd <- data.frame(sampleNames = fromf) + assaydata <- list2env(as(from, "list")) + lockEnvironment(assaydata, bindings = TRUE) + new("MSnExp", assayData = assaydata, + phenoData = new("NAnnotatedDataFrame", pd), featureData = fd, + processingData = process) +}) + +#' @rdname Spectra +#' +#' @examples +#' +#' ## Filter the object by MS level +#' filterMsLevel(spl, msLevel. = 1) +setMethod("filterMsLevel", "Spectra", function(object, msLevel.) { + if (missing(msLevel.)) return(object) + msLevel. <- as.numeric(msLevel.) + object[msLevel(object) %in% msLevel.] +}) ## Still to implement: ## quantify, method = c("trapezoidation", "max", "sum", reporters, strict = FALSE) diff --git a/man/Spectra.Rd b/man/Spectra.Rd index 23bc55bf7..561994eed 100644 --- a/man/Spectra.Rd +++ b/man/Spectra.Rd @@ -7,6 +7,7 @@ \alias{Spectra-class} \alias{show,Spectra-method} \alias{coerce,Spectra,list-method} +\alias{coerce,Spectra,MSnExp-method} \alias{mz,Spectra-method} \alias{intensity,Spectra-method} \alias{rtime,Spectra-method} @@ -33,6 +34,7 @@ \alias{filterMz,Spectra-method} \alias{pickPeaks,Spectra-method} \alias{smooth,Spectra-method} +\alias{filterMsLevel,Spectra-method} \title{List of Spectrum objects along with annotations} \usage{ Spectra(..., elementMetadata = NULL) @@ -93,6 +95,8 @@ Spectra(..., elementMetadata = NULL) \S4method{smooth}{Spectra}(x, method = c("SavitzkyGolay", "MovingAverage"), halfWindowSize = 2L, ...) + +\S4method{filterMsLevel}{Spectra}(object, msLevel.) } \arguments{ \item{...}{For \code{Spectra}: \linkS4class{Spectrum} object(s) or a \code{list} of @@ -122,7 +126,8 @@ for the MGF file.} around peaks.} \item{msLevel.}{For \code{clean}, \code{removePeaks}, \code{filterMz}: optionally specify -the MS level of the spectra on which the operation should be performed.} +the MS level of the spectra on which the operation should be performed. +For \code{filterMsLevels}: MS level(s) to which the \code{Spectra} should be reduced.} \item{t}{For \code{removePeaks}: \code{numeric(1)} specifying the threshold below which intensities are set to 0.} @@ -213,8 +218,6 @@ centroided from the actual peak data. \itemize{ \item \code{clean} \emph{cleans} each spectrum. See \code{\link[=clean]{clean()}} for more details. -\item \code{filterMz} filters the spectra by the specified \code{mz} range. See -\code{\link[=filterMz]{filterMz()}} for details. \item \code{pickPeaks} performs peak picking to generate centroided spectra. See \code{\link[=pickPeaks]{pickPeaks()}} for more details. \item \code{removePeaks} removes peaks lower than a threshold \code{t}. See @@ -321,6 +324,9 @@ file.remove(tmpf) writeMgfData(spl, tmpf) readLines(tmpf) + +## Filter the object by MS level +filterMsLevel(spl, msLevel. = 1) } \author{ Johannes Rainer diff --git a/tests/testthat/test_methods-Spectra.R b/tests/testthat/test_methods-Spectra.R index cd00f9553..b9235014f 100644 --- a/tests/testthat/test_methods-Spectra.R +++ b/tests/testthat/test_methods-Spectra.R @@ -12,15 +12,15 @@ test_that("mz, intensity, rtime work", { expect_true(length(mz(spl)) == 3) expect_equal(mz(spl[[2]]), mz(spl)[[2]]) expect_equal(mz(spl)[[3]], mz(sp3)) - + expect_true(length(intensity(spl)) == 3) expect_equal(intensity(spl[[2]]), intensity(spl)[[2]]) expect_equal(intensity(spl)[[3]], intensity(sp3)) - + expect_true(length(rtime(spl)) == 3) expect_equal(rtime(spl[[2]]), rtime(spl)[[2]]) expect_equal(rtime(spl)[[3]], rtime(sp3)) - + spl <- c(spl, Spectra(new("Spectrum2"))) expect_true(lengths(mz(spl))[4] == 0) expect_true(lengths(intensity(spl))[4] == 0) @@ -53,7 +53,7 @@ test_that("precursor* work", { expect_equal(precursorIntensity(spl), c(1234.4, NA, NA)) expect_equal(precScanNum(spl), c(NA_integer_, 34L, NA_integer_)) expect_true(is.integer(precScanNum(spl))) - + expect_equal(precursorMz(spl_), c(NA_real_, 2, NA_real_)) expect_equal(precursorCharge(spl_), rep(NA_integer_, length(spl_))) expect_equal(precursorIntensity(spl_), rep(NA_real_, length(spl_))) @@ -66,7 +66,7 @@ test_that("acquisitionNum and scanIndex work", { spl <- Spectra(sp1, sp2) expect_identical(acquisitionNum(spl), c(2L, 4L)) expect_identical(scanIndex(spl), c(1L, NA_integer_)) - + expect_equal(acquisitionNum(spl_), rep(NA_integer_, length(spl_))) expect_equal(scanIndex(spl_), rep(NA_integer_, length(spl_))) expect_true(is.integer(acquisitionNum(spl_))) @@ -199,7 +199,7 @@ test_that("removePeaks,Spectra works", { res_2 <- lapply(spl, removePeaks) expect_equal(res@listData, res_2) expect_equal(mcols(res)$id, 1:3) - + res <- removePeaks(spl, t = 10, msLevel. = 1) expect_true(is(res, "Spectra")) res_2 <- lapply(spl, removePeaks, t = 10, msLevel. = 1) @@ -253,7 +253,7 @@ test_that("combineSpectra,Spectra works", { ints2[11:20] <- c(15, 30, 60, 120, 300, 200, 90, 60, 30, 23) ints3 <- abs(rnorm(length(mzs), 10)) ints3[11:20] <- c(13, 20, 50, 100, 200, 100, 80, 40, 30, 20) - + ## Create the spectra. sp1 <- new("Spectrum1", mz = mzs + rnorm(length(mzs), sd = 0.01), intensity = ints1, rt = 1) @@ -263,7 +263,7 @@ test_that("combineSpectra,Spectra works", { intensity = ints3, rt = 3) sp4 <- new("Spectrum2", mz = 1:3, intensity = c(4, 8, 1)) sp5 <- new("Spectrum2", mz = 2:4, intensity = c(5, 8, 2)) - + spctra <- Spectra(sp1, sp2, sp3, elementMetadata = DataFrame(idx = 1:3, group = c("b", "a", "a"))) @@ -275,7 +275,7 @@ test_that("combineSpectra,Spectra works", { names(spctra) <- c("A", "B", "C") res <- combineSpectra(spctra) - + expect_error(combineSpectra(spctra, fcol = "other")) res <- combineSpectra(spctra, fcol = "group", mzd = 0.05) expect_equal(lengths(intensity(res)), c(b = 191, a = 191)) @@ -283,7 +283,7 @@ test_that("combineSpectra,Spectra works", { expect_equal(res[[1]], sp1) expect_equal(mcols(res), DataFrame(idx = c(1, 2), group = c("b", "a"), row.names = c("b", "a"))) - + spctra <- Spectra(sp1, sp2, sp3, sp4, sp5, elementMetadata = DataFrame(group = c("a", "b", "a", "c", "c"))) @@ -295,3 +295,53 @@ test_that("combineSpectra,Spectra works", { expect_equal(msLevel(res), c(a = 1, b = 1, c = 2)) expect_equal(intensity(res)[[3]], c(4, mean(c(8, 5)), mean(c(1, 8)), 2)) }) + +test_that("as,Spectra,list works", { + sps <- Spectra() + res <- as(sps, "list") + expect_true(length(res) == 0) + expect_true(is.list(res)) + + res <- as(spl_, "list") + expect_true(is.list(res)) + expect_equal(res, list(sp1, sp2, sp3)) +}) + +test_that("as,Spectra,MSnExp works", { + sps <- Spectra() + res <- as(sps, "MSnExp") + expect_true(is(res, "MSnExp")) + expect_true(length(res) == 0) + expect_true(validObject(res)) + + expect_error(as(spl_, "MSnExp")) + spl_2 <- filterMsLevel(spl_, 2) + res <- as(spl_2, "MSnExp") + expect_equal(unname(spectra(res)), as(spl_2, "list")) + res <- as(spl_2[2:1], "MSnExp") + expect_equal(unname(spectra(res)), as(spl_2[2:1], "list")) + mcols(spl_2) <- DataFrame(id = c("a", "b"), other = c("d", "e")) + res <- as(spl_2, "MSnExp") + expect_equal(fData(res)$id, mcols(spl_2)$id) + expect_equal(fData(res)$other, mcols(spl_2)$other) + expect_equal(unname(spectra(res)), as(spl_2, "list")) + + spl_1 <- filterMsLevel(spl_, 1) + res <- as(spl_1, "MSnExp") + expect_equal(spectra(res), list(`1` = sp3)) +}) + +test_that("filterMsLevel,Spectra works", { + res <- filterMsLevel(spl_, 1) + expect_equal(res, Spectra(sp3)) + + expect_equal(filterMsLevel(spl_), spl_) + expect_equal(filterMsLevel(spl_, 1:4), spl_) + + res <- filterMsLevel(spl_, 2) + expect_equal(res, Spectra(sp1, sp2)) + + res <- filterMsLevel(spl_, 4) + expect_true(is(res, "Spectra")) + expect_true(length(res) == 0) +})