From 71aa9620800a48052a27ef4c630c901581a66dd7 Mon Sep 17 00:00:00 2001 From: jotsetung Date: Fri, 26 Oct 2018 16:45:34 +0200 Subject: [PATCH 1/3] Add as,MSnExp,Spectra and as,Spectra,list #370 --- R/DataClasses.R | 6 ++++-- R/methods-MSnExp.R | 12 ++++++++++++ R/methods-Spectra.R | 4 ++++ man/MSnExp-class.Rd | 7 +++++++ man/Spectra.Rd | 3 +++ tests/testthat/test_MSnExp.R | 12 ++++++++++++ 6 files changed, 42 insertions(+), 2 deletions(-) diff --git a/R/DataClasses.R b/R/DataClasses.R index fa2bec640..e32af7818 100644 --- a/R/DataClasses.R +++ b/R/DataClasses.R @@ -676,8 +676,8 @@ setClass("Chromatograms", #' @name Spectra #' -#' @aliases Spectra-class show,Spectra-method -#' +#' @aliases Spectra-class show,Spectra-method coerce,Spectra,list-method +#' #' @title List of Spectrum objects along with annotations #' #' @description @@ -687,6 +687,8 @@ setClass("Chromatograms", #' the possibility to add arbitrary annotations to each individual #' `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). #' diff --git a/R/methods-MSnExp.R b/R/methods-MSnExp.R index 1e74f94b5..b390fbfd7 100644 --- a/R/methods-MSnExp.R +++ b/R/methods-MSnExp.R @@ -565,3 +565,15 @@ setAs("MSnExp", "data.frame", function(from) { }) as.data.frame.MSnExp <- function(x, row.names = NULL, optional=FALSE, ...) as(x, "data.frame") + +setAs("MSnExp", "Spectra", function(from) { + fdta <- fData(from) + red_cn <- c("fileIdx", "spIdx", "smoothed", "seqNum", "acquisitionNum", + "msLevel", "polarity", "originalPeaksCount", "totIonCurrent", + "retentionTime", "basePeakMZ", "basePeakIntensity", + "collisionEnergy", "ionisationEnergy", "precursorScanNum", + "precursorMZ", "precursorCharge", "precursorIntensity", + "mergedScan", "centroided", "spectrum") + fdta <- fdta[, !colnames(fdta) %in% red_cn, drop = FALSE] + Spectra(spectra(from), elementMetadata = DataFrame(fdta)) +}) diff --git a/R/methods-Spectra.R b/R/methods-Spectra.R index e6193300d..e96b4568a 100644 --- a/R/methods-Spectra.R +++ b/R/methods-Spectra.R @@ -514,6 +514,10 @@ setMethod("combineSpectra", "Spectra", function(object, fcol, ]) }) +setAs("Spectra", "list", function(from) { + from@listData +}) + ## Still to implement: ## quantify, method = c("trapezoidation", "max", "sum", reporters, strict = FALSE) diff --git a/man/MSnExp-class.Rd b/man/MSnExp-class.Rd index 8cb9b7612..73b9a8eb4 100644 --- a/man/MSnExp-class.Rd +++ b/man/MSnExp-class.Rd @@ -73,6 +73,7 @@ \alias{coerce,MSnExp,data.frame-method} \alias{as.data.frame.MSnExp} +\alias{coerce,MSnExp,Spectra-method} \title{The 'MSnExp' Class for MS Data And Meta-Data} @@ -274,6 +275,12 @@ values) and \code{"i"} (intensity values). } + \item{as}{\code{signature(object = "MSnExp", "Spectra")}: + Coerces the \code{MSnExp} object to a \code{\linkS4class{Spectra}} + object with all feature annotations added as metadata columns + (\code{mcols}). + } + } Filtering and subsetting functions: diff --git a/man/Spectra.Rd b/man/Spectra.Rd index 82d96a1dd..23bc55bf7 100644 --- a/man/Spectra.Rd +++ b/man/Spectra.Rd @@ -6,6 +6,7 @@ \alias{Spectra} \alias{Spectra-class} \alias{show,Spectra-method} +\alias{coerce,Spectra,list-method} \alias{mz,Spectra-method} \alias{intensity,Spectra-method} \alias{rtime,Spectra-method} @@ -145,6 +146,8 @@ for details.} the possibility to add arbitrary annotations to each individual \code{Spectrum} object. These can be accessed/set with the \code{\link[=mcols]{mcols()}} method. +\code{Spectra} objects can be created with the \code{Spectra} function. + Functions to access the individual spectra's attributes are available (listed below). diff --git a/tests/testthat/test_MSnExp.R b/tests/testthat/test_MSnExp.R index c3d3f4c5a..4aa96d9f0 100644 --- a/tests/testthat/test_MSnExp.R +++ b/tests/testthat/test_MSnExp.R @@ -597,3 +597,15 @@ test_that("plotXIC_MSnExp works", { expect_error(plotXIC_MSnExp(tmt_erwinia_in_mem_ms2)) }) + +test_that("as,MSnExp,Spectra works", { + res <- as(tmt_erwinia_in_mem_ms1, "Spectra") + expect_equal(res@listData, spectra(tmt_erwinia_in_mem_ms1)) + expect_true(ncol(mcols(res)) == 0) + + res <- as(sciex, "Spectra") + expect_equal(length(res), length(sciex)) + expect_equal(msLevel(res), msLevel(sciex)) + expect_equal(intensity(res), intensity(sciex)) + expect_true(ncol(mcols(res)) > 0) +}) From 9ea2c4a17179eed906516731004d3f3c91001db2 Mon Sep 17 00:00:00 2001 From: jotsetung Date: Wed, 7 Nov 2018 07:33:21 +0100 Subject: [PATCH 2/3] Add clean,Chromatograms (issue #354) --- DESCRIPTION | 2 +- NEWS | 7 +- NEWS.md | 8 +- R/functions-Chromatograms.R | 9 +-- R/methods-Chromatograms.R | 39 ++++++++-- R/methods-Spectra.R | 62 ++++++++------- man/Chromatograms-class.Rd | 15 ++++ tests/testthat/test_methods-Chromatograms.R | 83 ++++++++++++++++----- 8 files changed, 162 insertions(+), 63 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index dd3320821..bac1ae9f2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: MSnbase Title: Base Functions and Classes for Mass Spectrometry and Proteomics -Version: 2.9.0 +Version: 2.9.1 Description: MSnbase provides infrastructure for manipulation, processing and visualisation of mass spectrometry and proteomics data, ranging from raw to quantitative and diff --git a/NEWS b/NEWS index 16e1df3e0..e010215fe 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ # MSnbase 2.9 +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> + Changes in version 2.9.0 - New version for Bioc 3.9 devel @@ -20,7 +25,7 @@ Changes in version 2.7.12 Changes in version 2.7.11 -- Change default for `timeDomain` in `combineSpectra` and +- Change default for `timeDomain` in `combineSpectra` and `combineSpectraMovingWindow` to `FALSE` <2018-10-18 Thu> - Add new spectra combination function `consensusSpectrum` <2018-10-24 Wed> diff --git a/NEWS.md b/NEWS.md index 111e6f922..7577e1a1f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # MSnbase 2.9 +## Changes in version 2.9.1 +- Add clean,Chromatograms (issue + [#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> + ## Changes in version 2.9.0 - New version for Bioc 3.9 devel @@ -20,7 +26,7 @@ ## Changes in version 2.7.11 -- Change default for `timeDomain` in `combineSpectra` and +- Change default for `timeDomain` in `combineSpectra` and `combineSpectraMovingWindow` to `FALSE` <2018-10-18 Thu> - Add new spectra combination function `consensusSpectrum` <2018-10-24 Wed> diff --git a/R/functions-Chromatograms.R b/R/functions-Chromatograms.R index 635b20648..03fc44a18 100644 --- a/R/functions-Chromatograms.R +++ b/R/functions-Chromatograms.R @@ -39,11 +39,11 @@ #' #' @param featureData either a \code{data.frame} or \code{AnnotatedDataFrame} #' with additional information for each row of chromatograms. -#' +#' #' @param ... Additional parameters to be passed to the #' \code{\link[base]{matrix}} constructor, such as \code{nrow}, \code{ncol} #' and \code{byrow}. -#' +#' #' @rdname Chromatograms-class Chromatograms <- function(data, phenoData, featureData, ...) { if (missing(data)) @@ -112,7 +112,7 @@ Chromatograms <- function(data, phenoData, featureData, ...) { ## to the number of data points that were actually measured. lens <- lengths(x) maxLens <- max(lens) - + ints <- rts <- matrix(NA_real_, nrow = maxLens, ncol = length(x)) for (i in seq(along = x)) { if (lens[i]) { @@ -180,7 +180,7 @@ Chromatograms <- function(data, phenoData, featureData, ...) { #' `Chromatogram` objects in each row. #' #' @author Johannes Rainer -#' +#' #' @noRd .bin_Chromatograms <- function(object, binSize = 0.5, breaks = numeric(), fun = max) { @@ -196,4 +196,3 @@ Chromatograms <- function(data, phenoData, featureData, ...) { if (validObject(object)) object } - diff --git a/R/methods-Chromatograms.R b/R/methods-Chromatograms.R index 2369109b4..009d87365 100644 --- a/R/methods-Chromatograms.R +++ b/R/methods-Chromatograms.R @@ -28,7 +28,7 @@ setMethod("show", "Chromatograms", function(object) { } rn <- rownames(out) out <- rbind(rep("", ncol(out)), out) - rownames(out) <- c("", rn) + rownames(out) <- c("", rn) print(out, quote = FALSE, right = TRUE) } cat("phenoData with", length(varLabels(object@phenoData)), "variables\n") @@ -55,9 +55,9 @@ setAs("matrix", "Chromatograms", function(from) { #' object (with the exception of extracting a single element) #' unless \code{drop = TRUE} is specified. This is different from the #' default subsetting behaviour of \code{matrix}-like objects. -#' +#' #' @param x For all methods: a \code{Chromatograms} object. -#' +#' #' @param i For \code{[}: \code{numeric}, \code{logical} or \code{character} #' defining which row(s) to extract. #' @@ -123,7 +123,7 @@ setMethod("[", "Chromatograms", #' @param value For \code{[<-}: the replacement object(s). Can be a \code{list} #' of \code{\link{Chromatogram}} objects or, if length of \code{i} and #' \code{j} are 1, a single \code{\link{Chromatogram}} object. -#' +#' #' For \code{pData<-}: a \code{data.frame} with the number of rows matching #' the number of columns of \code{object}. #' @@ -163,7 +163,7 @@ setReplaceMethod("[", "Chromatograms", }) #' @rdname Chromatograms-class -#' +#' #' @description \code{plot}: plots a \code{Chromatograms} object. For each row #' in the object one plot is created, i.e. all \code{\link{Chromatogram}} #' objects in the same row are added to the same plot. @@ -182,11 +182,11 @@ setReplaceMethod("[", "Chromatograms", #' @param type For \code{plot}: the type of plot (see #' \code{\link[graphics]{plot}} for more details. Can be either a vector #' of length 1 or of length equal to \code{ncol(x)}. -#' +#' #' @inheritParams Chromatogram-class #' #' @examples -#' +#' #' ## Create some random Chromatogram objects #' ints <- abs(rnorm(123, mean = 200, sd = 32)) #' ch1 <- Chromatogram(rtime = seq_along(ints), intensity = ints, mz = 231) @@ -312,7 +312,7 @@ setMethod("isEmpty", "Chromatograms", function(x) { }) #' @rdname Chromatograms-class -#' +#' #' @description \code{featureNames}: returns the feature names of the #' \code{Chromatograms} object. setMethod("featureNames", "Chromatograms", function(object) @@ -463,3 +463,26 @@ setMethod("polarity", "Chromatograms", function(object) { #' #' @rdname Chromatograms-class setMethod("bin", "Chromatograms", .bin_Chromatograms) + +#' @description +#' +#' \code{clean}: removes 0-intensity data points. Either all of them +#' (with \code{all = TRUE}) or all except those adjacent to non-zero +#' intensities (\code{all = FALSE}; default). See \code{\link{clean}} +#' documentation for more details and examples. +#' +#' @param all for \code{clean}: \code{logical(1)} whether all 0 intensities +#' should be removed (\code{all = TRUE}), or whether 0-intensities +#' adjacent to peaks should be kept (\code{all = FALSE}; default). +#' +#' @param na.rm for \code{clean}: \code{logical(1)} whether all \code{NA} +#' intensities should be removed prior to clean 0 intensity data points. +#' +#' @rdname Chromatograms-class +setMethod("clean", "Chromatograms", function(object, all = FALSE, + na.rm = FALSE) { + object@.Data <- matrix(lapply(object, clean, all = all, na.rm = na.rm), + nrow = nrow(object), dimnames = dimnames(object)) + if (validObject(object)) + object +}) diff --git a/R/methods-Spectra.R b/R/methods-Spectra.R index e96b4568a..dc6b3b57f 100644 --- a/R/methods-Spectra.R +++ b/R/methods-Spectra.R @@ -71,7 +71,7 @@ setMethod("show", "Spectra", function(object) { #' [removePeaks()] for more details. #' #' - `smooth` *smooths* spectra. See [smooth()] for more details. -#' +#' #' @md #' #' @param all For `clean`: if `FALSE` original 0-intensity values are retained @@ -85,7 +85,7 @@ setMethod("show", "Spectra", function(object) { #' #' @param mz For `filterMz`: `numeric(2)` defining the lower and upper m/z #' for the filter. See [filterMz()] for details. -#' +#' #' @param t For `removePeaks`: `numeric(1)` specifying the threshold below #' which intensities are set to 0. #' @@ -115,7 +115,7 @@ setMethod("intensity", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the retention time values for the individual spectra @@ -125,7 +125,7 @@ setMethod("rtime", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the precursor m/z of each spectrum. @@ -138,7 +138,7 @@ setMethod("precursorMz", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the precursor charge of each spectrum. @@ -151,7 +151,7 @@ setMethod("precursorCharge", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the precursor scan number for each spectrum. @@ -164,7 +164,7 @@ setMethod("precScanNum", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the precursor intensity of each spectrum. @@ -178,7 +178,7 @@ setMethod("precursorIntensity", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the acquisition number of each spectrum. @@ -190,7 +190,7 @@ setMethod("acquisitionNum", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the scan index of each spectrum. @@ -202,7 +202,7 @@ setMethod("scanIndex", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Get the number of peaks per spectrum. @@ -212,7 +212,7 @@ setMethod("peaksCount", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Get the MS level of each spectrum. @@ -222,7 +222,7 @@ setMethod("msLevel", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Get the total ion current for each spectrum. @@ -232,7 +232,7 @@ setMethod("tic", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Get the total ion current for each spectrum. @@ -242,7 +242,7 @@ setMethod("ionCount", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the collision energy for each spectrum. @@ -255,7 +255,7 @@ setMethod("collisionEnergy", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Extract the file index for each spectrum. @@ -267,7 +267,7 @@ setMethod("fromFile", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Get the polarity for each spectrum. @@ -279,7 +279,7 @@ setMethod("polarity", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Whether spectra are smoothed (i.e. processed with the `smooth` @@ -290,7 +290,7 @@ setMethod("smoothed", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Are spectra empty (i.e. contain no peak data)? @@ -300,7 +300,7 @@ setMethod("isEmpty", "Spectra", function(x) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Do the spectra contain centroided data? @@ -310,7 +310,7 @@ setMethod("centroided", "Spectra", function(object) { }) #' @rdname Spectra -#' +#' #' @examples #' #' ## Do the spectra contain centroided data? Whether spectra are centroided @@ -338,14 +338,14 @@ setMethod("isCentroided", "Spectra", function(object) { #' for the MGF file. #' #' @md -#' +#' #' @examples #' #' ## Export the spectrum list to a MGF file. Values in metadata columns are #' ## exported as additional field for each spectrum. #' tmpf <- tempfile() #' writeMgfData(spl, tmpf) -#' +#' #' ## Evaluate the written output. The ID of each spectrum (defined in the #' ## "id" metadata column) is exported as field "ID". #' readLines(tmpf) @@ -413,7 +413,7 @@ setMethod("smooth", "Spectra", function(x, method = c("SavitzkyGolay", #' @rdname combineSpectra #' #' @aliases combineSpectra -#' +#' #' @title Combine Spectra #' #' `combineSpectra` combines spectra in a [MSnExp-class] or [Spectra-class] @@ -438,7 +438,7 @@ setMethod("smooth", "Spectra", function(x, method = c("SavitzkyGolay", #' @return A `Spectra` or `MSnExp` object with combined spectra. Metadata #' (`mcols`) and all spectrum attributes other than `mz` and `intensity` #' are taken from the first `Spectrum` in each set. -#' +#' #' @md #' #' @author Johannes Rainer, Laurent Gatto @@ -446,7 +446,7 @@ setMethod("smooth", "Spectra", function(x, method = c("SavitzkyGolay", #' @seealso [meanMzInts()] for a function to combine spectra. #' #' @examples -#' +#' #' set.seed(123) #' mzs <- seq(1, 20, 0.1) #' ints1 <- abs(rnorm(length(mzs), 10)) @@ -473,7 +473,7 @@ setMethod("smooth", "Spectra", function(x, method = c("SavitzkyGolay", #' #' ## All values other than m/z and intensity are kept from the first spectrum #' rtime(res) -#' +#' #' ## Plot the individual and the merged spectrum #' par(mfrow = c(2, 1), mar = c(4.3, 4, 1, 1)) #' plot(mz(sp1), intensity(sp1), xlim = range(mzs[5:25]), type = "h", col = "red") @@ -481,13 +481,13 @@ setMethod("smooth", "Spectra", function(x, method = c("SavitzkyGolay", #' points(mz(sp3), intensity(sp3), type = "h", col = "blue") #' plot(mz(res[[1]]), intensity(res[[1]]), type = "h", #' col = "black", xlim = range(mzs[5:25])) -#' +#' #' ## Combine spectra in two sets. #' res <- combineSpectra(spctra, fcol = "group", mzd = 0.05) #' res #' #' rtime(res) -#' +#' #' ## Plot the individual and the merged spectra #' par(mfrow = c(3, 1), mar = c(4.3, 4, 1, 1)) #' plot(mz(sp1), intensity(sp1), xlim = range(mzs[5:25]), type = "h", col = "red") @@ -518,6 +518,12 @@ setAs("Spectra", "list", function(from) { from@listData }) +## setAs("Spectra", "MSnExp", function(from) { +## ## mcols -> featureData +## ## empty phenoData +## ## empty processing +## ## spectra -> spectra +## }) ## Still to implement: ## quantify, method = c("trapezoidation", "max", "sum", reporters, strict = FALSE) diff --git a/man/Chromatograms-class.Rd b/man/Chromatograms-class.Rd index 29d44489a..258a18568 100644 --- a/man/Chromatograms-class.Rd +++ b/man/Chromatograms-class.Rd @@ -32,6 +32,7 @@ \alias{mz,Chromatograms-method} \alias{polarity,Chromatograms-method} \alias{bin,Chromatograms-method} +\alias{clean,Chromatograms-method} \title{Container for multiple Chromatogram objects} \usage{ Chromatograms(data, phenoData, featureData, ...) @@ -90,6 +91,8 @@ Chromatograms(data, phenoData, featureData, ...) \S4method{bin}{Chromatograms}(object, binSize = 0.5, breaks = numeric(), fun = max) + +\S4method{clean}{Chromatograms}(object, all = FALSE, na.rm = FALSE) } \arguments{ \item{data}{A \code{list} of \code{\link{Chromatogram}} objects.} @@ -160,6 +163,13 @@ row.} \item{fun}{for \code{bin}: function to be used to aggregate the intensity values falling within each bin.} + +\item{all}{for \code{clean}: \code{logical(1)} whether all 0 intensities +should be removed (\code{all = TRUE}), or whether 0-intensities +adjacent to peaks should be kept (\code{all = FALSE}; default).} + +\item{na.rm}{for \code{clean}: \code{logical(1)} whether all \code{NA} +intensities should be removed prior to clean 0 intensity data points.} } \value{ For \code{[}: the subset of the \code{Chromatograms} object. If a @@ -265,6 +275,11 @@ as a two-column \code{matrix} (with columns \code{"mzmin"} and along the retention time axis. By default, individual \code{Chromatogram} objects of one row are binned into the same bins. The function returns a \code{Chromatograms} object with binned chromatograms. + +\code{clean}: removes 0-intensity data points. Either all of them +(with \code{all = TRUE}) or all except those adjacent to non-zero +intensities (\code{all = FALSE}; default). See \code{\link{clean}} +documentation for more details and examples. } \details{ The \code{Chromatograms} class extends the base \code{matrix} class diff --git a/tests/testthat/test_methods-Chromatograms.R b/tests/testthat/test_methods-Chromatograms.R index 53fc9c0b8..2601be780 100644 --- a/tests/testthat/test_methods-Chromatograms.R +++ b/tests/testthat/test_methods-Chromatograms.R @@ -9,7 +9,7 @@ test_that("[,Chromatograms works", { ints <- abs(rnorm(40, sd = 34)) ch3 <- Chromatogram(rtime = 1:length(ints), ints) chrs <- Chromatograms(list(ch, ch1, ch2, ch3), nrow = 2) - + ## o Subset using indices expect_true(is(chrs[1, 1], "Chromatogram")) expect_equal(chrs[1, 2], ch2) @@ -17,7 +17,7 @@ test_that("[,Chromatograms works", { expect_equal(chrs[1, , drop = TRUE], list(`1` = ch, `2` = ch2)) expect_equal(chrs[1, , drop = FALSE], Chromatograms(list(ch, ch2), nrow = 1)) ## Test the default - expect_equal(chrs[1, ], Chromatograms(list(ch, ch2), nrow = 1)) + expect_equal(chrs[1, ], Chromatograms(list(ch, ch2), nrow = 1)) ## extract a column expect_equal(chrs[, 2, drop = TRUE], list(`1` = ch2, `2` = ch3)) res <- chrs[, 2, drop = FALSE] @@ -47,7 +47,7 @@ test_that("[,Chromatograms works", { res <- chrs[2, ] expect_equal(rownames(res), "2") expect_equal(featureNames(res), "2") - + ## o Subset using logical chrs <- Chromatograms(list(ch, ch1, ch2, ch3), nrow = 2) expect_true(is(chrs[c(TRUE, FALSE), c(TRUE, FALSE)], "Chromatogram")) @@ -137,13 +137,13 @@ test_that("[<-,Chromatograms works", { expect_equal(chrs[, 2, drop = TRUE], list(`1` = ch2, `2` = ch3)) chrs[2, 1] <- list(ch4) expect_equal(chrs[2, 1], ch4) - + chrs[, "a"] <- list(ch2, ch1) expect_equal(chrs[, 1, drop = TRUE], list(`1` = ch2, `2` = ch1)) expect_error(chrs[, 1] <- list(ch, ch2, ch3)) - + chrs[, c(TRUE, FALSE)] <- list(ch4, ch4) - expect_equal(chrs[, 1, drop = TRUE], list(`1` = ch4, `2` = ch4)) + expect_equal(chrs[, 1, drop = TRUE], list(`1` = ch4, `2` = ch4)) }) test_that("plot,Chromatograms works", { @@ -206,12 +206,12 @@ test_that("phenoData,pData,pData<-,Chromatograms works", { rownames(pData(pd_exp)) <- NULL pd_exp <- as(pd_exp, "NAnnotatedDataFrame") expect_equal(phenoData(chrs), pd_exp) - + ## Check error when assigning a phenoData with different names pd <- data.frame(name = letters[1:2], idx = 1:2) rownames(pd) <- letters[1:2] expect_error(pData(chrs) <- pd) - + pd <- data.frame(name = letters[1:2], idx = 1:2) chrs <- Chromatograms(list(ch, ch1, ch2, ch3), nrow = 2, phenoData = AnnotatedDataFrame(pd)) @@ -283,12 +283,12 @@ test_that("featureData,fData,fData<-,Chromatograms works", { fd_exp <- annotatedDataFrameFrom(matrix(ncol = 2, nrow = 2), byrow = TRUE) expect_equal(featureData(chrs), fd_exp) - + ## Check error when assigning a featureData with different names fd <- data.frame(name = letters[1:2], idx = 1:2) rownames(fd) <- letters[1:2] expect_error(fData(chrs) <- pd) - + fd <- data.frame(name = letters[1:2], idx = 1:2) chrs <- Chromatograms(list(ch, ch1, ch2, ch3), nrow = 2, featureData = fd) @@ -320,11 +320,11 @@ test_that("isEmpty,Chromatograms works", { expect_true(!isEmpty(chrs)) plot(chrs) - + chrs <- Chromatograms() expect_true(isEmpty(chrs)) expect_warning(plot(chrs)) - + ints <- rep(NA_real_, 105) ch1 <- Chromatogram(rtime = 1:length(ints), ints) ints <- rep(NA_real_, 64) @@ -332,7 +332,7 @@ test_that("isEmpty,Chromatograms works", { chrs <- Chromatograms(list(ch1, ch2), nrow = 2) expect_true(isEmpty(chrs)) expect_warning(plot(chrs)) - + ## Only one row is empty. ints <- rep(NA_real_, 105) ch1 <- Chromatogram(rtime = 1:length(ints), ints) @@ -377,11 +377,11 @@ test_that(".mz_chromatograms, precursorMz etc,Chromatograms works", { expect_true(all(is.na(res))) expect_equal(colnames(res), c("mzmin", "mzmax")) expect_equal(nrow(res), nrow(chrs)) - + ## method implementations: ## precursorMz expect_true(nrow(precursorMz(Chromatograms())) == 0) - + ## with precursor m/z data in the featureData data.frame chrs_f <- chrs fData(chrs_f) <- data.frame(precursorIsolationWindowTargetMZ = c(123, 456)) @@ -391,7 +391,7 @@ test_that(".mz_chromatograms, precursorMz etc,Chromatograms works", { expect_equal(res[, "mzmin"], res[, "mzmax"]) expect_equal(res[, "mzmin"], c(123, 456)) expect_equal(precursorMz(chrs_f), res) - + ## Extracting precursor m/z data from the Chromatogram objects. res <- MSnbase:::.mz_chromatograms(chrs) expect_true(all(is.na(res))) @@ -427,7 +427,7 @@ test_that(".mz_chromatograms, precursorMz etc,Chromatograms works", { expect_equal(res[, "mzmin"], res[, "mzmax"]) expect_equal(res[, "mzmin"], c(3, 5)) expect_equal(res, productMz(chrs_f)) - + chrs_2 <- chrs chrs_2[1, 1]@productMz <- range(5) expect_error(MSnbase:::.mz_chromatograms(chrs_2, "productMz"), @@ -444,7 +444,7 @@ test_that(".mz_chromatograms, precursorMz etc,Chromatograms works", { expect_true(all(polarity(chrs) == -1)) fData(chrs)$polarity <- c(1, 1) expect_true(all(polarity(chrs) == 1)) - + ## With a real object. on_disk <- microtofq_on_disk chrs <- chromatogram(on_disk, mz = c(123.4, 123.6), rt = c(35, 48)) @@ -467,7 +467,7 @@ test_that(".bin_Chromatograms and bin,Chromatograms work", { ch3 <- Chromatogram(rtime = 1:length(ints), ints) chrs <- Chromatograms(list(ch, ch1, ch2, ch3), nrow = 2) - chrsb <- MSnbase:::.bin_Chromatograms(chrs, binSize = 2) + chrsb <- .bin_Chromatograms(chrs, binSize = 2) ## 1st row: expect_equal(rtime(chrsb[1, 1]), rtime(chrsb[1, 2])) @@ -484,3 +484,48 @@ test_that(".bin_Chromatograms and bin,Chromatograms work", { expect_true(max(rtime(chrsb[2, 1])) >= max(rtime(chrs[2, 1]))) expect_equal(chrsb[2, 2], bin(chrs[2, 2], binSize = 2)) }) + +test_that("clean,Chromatograms works", { + chr1 <- Chromatogram(rtime = 1:10, + intensity = c(0, 3, 5, 0, 0, 0, 8, 9, 0, 9)) + chr2 <- Chromatogram(rtime = 1:12, + intensity = c(0, 0, 0, 3, 5, 0, 0, 0, 8, 9, 0, 9)) + chr3 <- Chromatogram(rtime = 1:8, + intensity = c(3, 5, 0, 0, 8, 9, 0, 9)) + chr4 <- Chromatogram(rtime = 1:12, + intensity = c(NA, 5, 0, 0, 0, 8, 9, 0, 9, 0, 0, 0)) + chr5 <- Chromatogram(rtime = 1:5, + intensity = c(0, 0, 0, 0, 0)) + chr6 <- Chromatogram(rtime = 1:9, + intensity = c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + chrs <- Chromatograms(list(chr1, chr2, chr3, chr4, chr5, chr6), nrow = 2, + phenoData = AnnotatedDataFrame(data.frame(id = 5:7)), + featureData = AnnotatedDataFrame(data.frame(mz = 3:4))) + res <- clean(chrs) + expect_equal(fData(res), fData(chrs)) + expect_equal(pData(res), pData(chrs)) + expect_equal(intensity(res[1, 1]), c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + expect_equal(intensity(res[2, 1]), c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + expect_equal(intensity(res[1, 2]), c(3, 5, 0, 0, 8, 9, 0, 9)) + expect_equal(intensity(res[2, 2]), c(NA, 5, 0, 0, 8, 9, 0, 9, 0)) + expect_equal(intensity(res[1, 3]), numeric()) + expect_equal(intensity(res[2, 3]), c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + + res <- clean(chrs, na.rm = TRUE) + expect_equal(intensity(res[1, 1]), c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + expect_equal(intensity(res[2, 1]), c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + expect_equal(intensity(res[1, 2]), c(3, 5, 0, 0, 8, 9, 0, 9)) + expect_equal(intensity(res[2, 2]), c(5, 0, 0, 8, 9, 0, 9, 0)) + expect_equal(intensity(res[1, 3]), numeric()) + expect_equal(intensity(res[2, 3]), c(0, 3, 5, 0, 0, 8, 9, 0, 9)) + + res <- clean(chrs, all = TRUE) + expect_equal(fData(res), fData(chrs)) + expect_equal(pData(res), pData(chrs)) + expect_equal(intensity(res[1, 1]), c(3, 5, 8, 9, 9)) + expect_equal(intensity(res[2, 1]), c(3, 5, 8, 9, 9)) + expect_equal(intensity(res[1, 2]), c(3, 5, 8, 9, 9)) + expect_equal(intensity(res[2, 2]), c(5, 8, 9, 9)) + expect_equal(intensity(res[1, 3]), numeric()) + expect_equal(intensity(res[2, 3]), c(3, 5, 8, 9, 9)) +}) From f889296c2ed219867d52e77cdff77adfe00e0a97 Mon Sep 17 00:00:00 2001 From: jotsetung Date: Wed, 7 Nov 2018 08:45:04 +0100 Subject: [PATCH 3/3] 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) +})