From 91aafbb7fb4684a7fc21e85103974a3825b42a33 Mon Sep 17 00:00:00 2001 From: Johannes Rainer Date: Wed, 11 Sep 2024 06:46:25 +0200 Subject: [PATCH] feat: add a function to coerce from Spectra to MSnbase::MSpectra - Add backward compatibility: support changing from a `Spectra` object to a `MSnbase::MSpectra` object using the `as()` method. - Add unit tests conditional to the installation of the *MSnbase* package. --- DESCRIPTION | 4 +- NEWS.md | 5 +++ R/Spectra-functions.R | 59 +++++++++++++++++++++++++ R/Spectra.R | 15 +++++++ man/Spectra.Rd | 9 ++++ tests/testthat/test_Spectra-functions.R | 10 +++++ tests/testthat/test_Spectra.R | 10 +++++ 7 files changed, 111 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index c233fc3c..d2f6926a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: Spectra Title: Spectra Infrastructure for Mass Spectrometry Data -Version: 1.15.7 +Version: 1.15.8 Description: The Spectra package defines an efficient infrastructure for storing and handling mass spectrometry spectra and functionality to subset, process, visualize and compare spectra data. It provides different @@ -66,6 +66,8 @@ Suggests: vdiffr (>= 1.0.0), msentropy, patrick +Enhances: + MSnbase License: Artistic-2.0 LazyData: false VignetteBuilder: knitr diff --git a/NEWS.md b/NEWS.md index 49e8e289..d4ee09e7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,10 @@ # Spectra 1.15 +## Changes in 1.15.8 + +- Add backward compatibility by supporting to change from a `Spectra` to a + *MSnbase* `MSpectra` object using `as()`. + ## Changes in 1.15.7 - Change `estimatePrecursorIntensity()` to a method to avoid overrides/clashes diff --git a/R/Spectra-functions.R b/R/Spectra-functions.R index 517452c4..eb6c985e 100644 --- a/R/Spectra-functions.R +++ b/R/Spectra-functions.R @@ -1292,3 +1292,62 @@ filterPeaksRanges <- function(object, ..., keep = TRUE) { "user-provided ranges for ", length(variables), " variables") object } + +#' Coercion method from `Spectra` to `MSnbase::MSpectra`. +#' +#' @noRd +.spectra_to_spectrum_list <- function(x, chunkSize = 100) { + requireNamespace("MSnbase", quietly = TRUE) + spectrapply(x, function(z) { + msl <- msLevel(z) + r <- vector("list", length = length(msl)) + i <- which(msl == 1L) + j <- which(msl > 1L) + if (length(i)) { + z_1 <- z[i] + mzs <- mz(z_1) + ints <- intensity(z_1) + l <- lengths(mzs) + r[i] <- MSnbase:::Spectra1_mz_sorted( + peaksCount = l, + rt = rtime(z_1), + acquisitionNum = acquisitionNum(z_1), + scanIndex = scanIndex(z_1), + tic = sum(ints), + mz = unlist(mzs), + intensity = unlist(ints), + fromFile = rep(NA_integer_, length(i)), + centroided = centroided(z_1), + smoothed = smoothed(z_1), + polarity = polarity(z_1), + nvalues = l) + } + if (length(j)) { + z_2 <- z[j] + mzs <- mz(z_2) + ints <- intensity(z_2) + l <- lengths(mzs) + r[j] <- MSnbase:::Spectra2_mz_sorted( + msLevel = msl[j], + peaksCount = l, + rt = rtime(z_2), + acquisitionNum = acquisitionNum(z_2), + scanIndex = scanIndex(z_2), + tic = sum(ints), + mz = unlist(mzs), + intensity = unlist(intensity(z_2)), + fromFile = rep(NA_integer_, length(j)), + centroided = centroided(z_2), + smoothed = smoothed(z_2), + polarity = polarity(z_2), + merged = rep(1, length(j)), + precScanNum = precScanNum(z_2), + precursorMz = precursorMz(z_2), + precursorIntensity = precursorIntensity(z_2), + precursorCharge = precursorCharge(z_2), + collisionEnergy = collisionEnergy(z_2), + nvalues = l) + } + r + }, chunkSize = chunkSize) +} diff --git a/R/Spectra.R b/R/Spectra.R index 76a467c5..d8584353 100644 --- a/R/Spectra.R +++ b/R/Spectra.R @@ -6,6 +6,7 @@ NULL #' @aliases Spectra-class [,Spectra-method #' @aliases uniqueMsLevels uniqueMsLevels,Spectra-method #' @aliases combinePeaks +#' @aliases msLevel #' #' @name Spectra #' @@ -55,6 +56,7 @@ NULL #' #' See also [this issue](https://github.com/lgatto/MSnbase/issues/525). #' +#' #' @section Creation of objects, conversion, changing the backend and export: #' #' `Spectra` classes can be created with the `Spectra()` constructor function @@ -146,6 +148,7 @@ NULL #' that were moved to another file system or computer, these functions allow to #' adjust/adapt the base file path. #' +#' #' @section Accessing spectra data: #' #' - `$`, `$<-`: gets (or sets) a spectra variable for all spectra in `object`. @@ -331,6 +334,7 @@ NULL #' - `uniqueMsLevels()`: get the unique MS levels available in `object`. This #' function is supposed to be more efficient than `unique(msLevel(object))`. #' +#' #' @section Filter spectra data: #' #' Filter a `Spectra` object based on the spectra data. This includes subset @@ -799,6 +803,13 @@ NULL #' level(s). #' #' +#' @section Backward compatibility: +#' +#' `Spectra` objects can be coerced to the older `MSpectra` objects from the +#' *MSnbase* package using the `as()` function (e.g. `as(sps, "MSpectra")` +#' where `sps` is a `Spectra` object). +#' +#' #' @return See individual method description for the return value. #' #' @param acquisitionNum for `filterPrecursorScan()`: `integer` with the @@ -1788,6 +1799,10 @@ setAs("Spectra", "SimpleList", function(from, to) { peaksData(from) }) +setAs("Spectra", "MSpectra", function(from) { + MSnbase::MSpectra(.spectra_to_spectrum_list(from, chunkSize = 1000)) +}) + #' @rdname Spectra setMethod("centroided", "Spectra", function(object) { centroided(object@backend) diff --git a/man/Spectra.Rd b/man/Spectra.Rd index b4f87b54..c346d836 100644 --- a/man/Spectra.Rd +++ b/man/Spectra.Rd @@ -18,6 +18,7 @@ \alias{uniqueMsLevels} \alias{uniqueMsLevels,Spectra-method} \alias{combinePeaks} +\alias{msLevel} \alias{Spectra,missing-method} \alias{Spectra,MsBackend-method} \alias{Spectra,character-method} @@ -1567,6 +1568,14 @@ level(s). } } +\section{Backward compatibility}{ + + +\code{Spectra} objects can be coerced to the older \code{MSpectra} objects from the +\emph{MSnbase} package using the \code{as()} function (e.g. \code{as(sps, "MSpectra")} +where \code{sps} is a \code{Spectra} object). +} + \examples{ ## Create a Spectra providing a `DataFrame` containing the spectrum data. diff --git a/tests/testthat/test_Spectra-functions.R b/tests/testthat/test_Spectra-functions.R index 8df50d71..a7b3d20b 100644 --- a/tests/testthat/test_Spectra-functions.R +++ b/tests/testthat/test_Spectra-functions.R @@ -923,3 +923,13 @@ test_that("filterPeaksRanges,Spectra works", { a <- peaksData(res)[[2L]] expect_true(nrow(a) == 0) }) + +test_that(".spectra_to_spectrum_list works", { + ## With MSnbase in Enhances we would need to call it like below. + if (requireNamespace("MSnbase", quietly = TRUE)) { + ## library(MSnbase) # MSnbase needs to be in Suggests + a <- .spectra_to_spectrum_list(sps_dda, chunkSize = 5000) + expect_true(is.list(a)) + expect_equal(length(a), length(sps_dda)) + } +}) diff --git a/tests/testthat/test_Spectra.R b/tests/testthat/test_Spectra.R index e81efdcb..54ac0ba3 100644 --- a/tests/testthat/test_Spectra.R +++ b/tests/testthat/test_Spectra.R @@ -1939,3 +1939,13 @@ test_that("estimatePrecursorIntensity works", { res_both <- estimatePrecursorIntensity(both) expect_equal(res_second, res_both[510:length(res_both)]) }) + +test_that("coersion from Spectra to MSpectra works", { + ## With MSnbase in Enhances we would need to call it like below + if (requireNamespace("MSnbase", quietly = TRUE)) { + ## library(MSnbase) # MSnbase needs to be in Suggests + a <- as(sps_dda, "MSpectra") + expect_s4_class(a, "MSpectra") + expect_equal(unname(msLevel(a)), msLevel(sps_dda)) + } +})