diff --git a/DESCRIPTION b/DESCRIPTION index 6e87cf88..841cffe8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: Spectra Title: Spectra Infrastructure for Mass Spectrometry Data -Version: 1.11.11 +Version: 1.11.12 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 diff --git a/NEWS.md b/NEWS.md index ffdf5fc3..fcab3669 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # Spectra 1.11 +## Changes in 1.11.12 + +- Fix issue with `bin` function (see + [issue #302](https://github.com/rformassspectrometry/Spectra/issues/303)). + Addition of `zero.rm` parameter to prevent creation of *empty* bins. + ## Changes in 1.11.11 - Fix issue with `filterFourierTransformArtefacts` function (see [issue diff --git a/R/Spectra.R b/R/Spectra.R index b62549ab..976492bf 100644 --- a/R/Spectra.R +++ b/R/Spectra.R @@ -1049,6 +1049,10 @@ NULL #' @param z For `filterPrecursorCharge`: `integer()` with the precursor charges #' to be used as filter. #' +#' @param zero.rm `logical`. For `bin`: indicating whether to remove bins with +#' zero intensity. Defaults to `TRUE`, meaning the function will discard +#' bins created with an intensity of 0 to enhance memory efficiency. +#' #' @param ... Additional arguments. #' #' @author Sebastian Gibb, Johannes Rainer, Laurent Gatto @@ -2437,7 +2441,7 @@ setMethod("reset", "Spectra", function(object, ...) { #' @exportMethod bin setMethod("bin", "Spectra", function(x, binSize = 1L, breaks = NULL, msLevel. = uniqueMsLevels(x), - FUN = sum) { + FUN = sum, zero.rm = TRUE) { if (!.check_ms_level(x, msLevel.)) return(x) if (!length(breaks)) { @@ -2449,7 +2453,7 @@ setMethod("bin", "Spectra", function(x, binSize = 1L, breaks = NULL, } mids <- (breaks[-length(breaks)] + breaks[-1L]) / 2 x <- addProcessing(x, .peaks_bin, breaks = breaks, mids = mids, - agg_fun = FUN, msLevel = msLevel., + agg_fun = FUN, msLevel = msLevel., zero.rm = zero.rm, spectraVariables = "msLevel") x@processing <- .logging(x@processing, "Spectra of MS level(s) ", diff --git a/R/peaks-functions.R b/R/peaks-functions.R index 65abec60..35b587f3 100644 --- a/R/peaks-functions.R +++ b/R/peaks-functions.R @@ -180,6 +180,11 @@ NULL #' #' @param mids mid points. This parameter is mandatory. #' +#' @param zero.rm `logical` indicating whether to remove bins with zero +#' intensity. Defaults to `TRUE`, meaning the function will discard bins +#' created with an intensity of 0 to enhance memory efficiency. +#' +#' #' @inheritParams .peaks_remove #' #' @return `matrix` with columns `"mz"` and `"intensity"` @@ -191,12 +196,15 @@ NULL by = binSize), agg_fun = sum, mids, - msLevel = spectrumMsLevel, ...) { + msLevel = spectrumMsLevel, zero.rm = TRUE, ...) { if (!(spectrumMsLevel %in% msLevel)) return(x) bins <- MsCoreUtils::bin(x[, 2], x[, 1], size = binSize, breaks = breaks, FUN = agg_fun, returnMids = FALSE) - cbind(mz = mids, intensity = bins) + if (zero.rm) { + keep <- which(bins != 0) + cbind(mz = mids[keep], intensity = bins[keep]) + } else cbind(mz = mids, intensity = bins) } #' @importFrom stats quantile diff --git a/man/Spectra.Rd b/man/Spectra.Rd index 7c7d76e5..2c22a0d2 100644 --- a/man/Spectra.Rd +++ b/man/Spectra.Rd @@ -387,7 +387,14 @@ filterPrecursorPeaks( \S4method{reset}{Spectra}(object, ...) -\S4method{bin}{Spectra}(x, binSize = 1L, breaks = NULL, msLevel. = uniqueMsLevels(x), FUN = sum) +\S4method{bin}{Spectra}( + x, + binSize = 1L, + breaks = NULL, + msLevel. = uniqueMsLevels(x), + FUN = sum, + zero.rm = TRUE +) \S4method{compareSpectra}{Spectra,Spectra}( x, @@ -686,6 +693,10 @@ Defaults to \code{binSize = 1}.} \item{breaks}{For \code{bin}: \code{numeric} defining the m/z breakpoints between bins.} +\item{zero.rm}{\code{logical}. For \code{bin}: indicating whether to remove bins with +zero intensity. Defaults to \code{TRUE}, meaning the function will discard +bins created with an intensity of 0 to enhance memory efficiency.} + \item{MAPFUN}{For \code{compareSpectra}: function to map/match peaks between the two compared spectra. See \code{\link[=joinPeaks]{joinPeaks()}} for more information and possible functions.} diff --git a/tests/testthat/test_Spectra.R b/tests/testthat/test_Spectra.R index 79380d70..e22462cc 100644 --- a/tests/testthat/test_Spectra.R +++ b/tests/testthat/test_Spectra.R @@ -1105,9 +1105,9 @@ test_that("filterRt,Spectra works", { test_that("bin,Spectra works", { sps <- Spectra(tmt_mzr) pks <- peaksData(sps) - res <- bin(sps, binSize = 2) + res <- bin(sps, binSize = 2, zero.rm = FALSE) expect_true(length(res@processingQueue) == 1) - res1 <- bin(sps, msLevel = 1, binSize = 2) + res1 <- bin(sps, msLevel = 1, binSize = 2, zero.rm = FALSE) expect_identical(peaksData(res1)[res1$msLevel == 2], pks[sps$msLevel == 2]) @@ -1115,7 +1115,7 @@ test_that("bin,Spectra works", { mzr <- range(unlist(mz(sps))) brks <- MsCoreUtils:::.fix_breaks( seq(floor(mzr[1]), ceiling(mzr[2]), by = 2), mzr) - res1 <- bin(sps, msLevel = 1, breaks = brks) + res1 <- bin(sps, msLevel = 1, breaks = brks, zero.rm = FALSE) res1_pks <- peaksData(res1) res_pks <- peaksData(res) expect_identical(res1_pks[res1$msLevel == 1], diff --git a/tests/testthat/test_peaks-functions.R b/tests/testthat/test_peaks-functions.R index 80675c1a..b7204b46 100644 --- a/tests/testthat/test_peaks-functions.R +++ b/tests/testthat/test_peaks-functions.R @@ -75,7 +75,8 @@ test_that(".peaks_bin works", { brks <- seq(min(x), max(x), by = 1L) brks <- MsCoreUtils:::.fix_breaks(brks, range(x)) mids <- seq_len(length(brks) -1) - res <- .peaks_bin(x, spectrumMsLevel = 1L, breaks = brks, mids = mids) + res <- .peaks_bin(x, spectrumMsLevel = 1L, breaks = brks, mids = mids, + zero.rm = FALSE) expect_identical(res[-1, 2], x[, 2]) expect_identical(res[, 1], as.numeric(mids)) @@ -83,22 +84,34 @@ test_that(".peaks_bin works", { brks <- MsCoreUtils:::.fix_breaks(brks, range(x)) mids <- (brks[-length(brks)] + brks[-1L]) / 2 res <- .peaks_bin(x, spectrumMsLevel = 1L, breaks = brks, - mids = mids) + mids = mids, zero.rm = FALSE) expect_equal(res[, 1], seq(1, 25, by = 2)) expect_equal(res[, 2], c(0, 3, 4, 0, 0, 4, 16, 3, 1, 2, 1, 15, 6)) res <- .peaks_bin(x, spectrumMsLevel = 1L, breaks = brks, - agg_fun = max, mids = mids) + agg_fun = max, mids = mids, zero.rm = FALSE) expect_equal(res[, 1], seq(1, 25, by = 2)) expect_equal(res[, 2], c(0, 2, 3, 0, 0, 3, 10, 2, 1, 2, 1, 10, 5)) - res <- .peaks_bin(x, spectrumMsLevel = 1L, msLevel = 2L, binSize = 2L) + res <- .peaks_bin(x, spectrumMsLevel = 1L, msLevel = 2L, binSize = 2L, + zero.rm = FALSE) expect_identical(res, x) brks <- seq(0.5, 30.5, by = 2) mids <- seq((length(brks) - 1)) res <- Spectra:::.peaks_bin(x, breaks = brks, mids = mids, - spectrumMsLevel = 1L) + spectrumMsLevel = 1L, zero.rm = FALSE) expect_equal(res[, 1], mids) expect_equal(res[, 2], c(1, 5, 1, 0, 1, 13, 8, 1, 3, 0, 6, 15, 1, 0, 0)) + + breaks <- seq(0, 1000, by = 0.01) + mids <- (breaks[-length(breaks)] + breaks[-1L]) / 2 + res_true <- Spectra:::.peaks_bin(sciex_pks[[1]], breaks = breaks, mids = mids, + spectrumMsLevel = 1L, zero.rm = TRUE) + res_false <- Spectra:::.peaks_bin(sciex_pks[[1]], breaks = breaks, mids = mids, + spectrumMsLevel = 1L, zero.rm = FALSE) + expect_true(all(res_true[,"intensity"] != 0)) + expect_false(all(res_false[,"intensity"] != 0)) + expect_false(length(res_true) == length(res_false)) + }) test_that("joinPeaksNone works", { diff --git a/vignettes/Spectra.Rmd b/vignettes/Spectra.Rmd index 8ffc7977..1065d665 100644 --- a/vignettes/Spectra.Rmd +++ b/vignettes/Spectra.Rmd @@ -955,10 +955,11 @@ Another way of comparing spectra would be to *bin* the spectra and to cluster them based on similar intensity values. Spectra binning ensures that the binned m/z values are comparable across all spectra. Below we bin our spectra using a bin size of 0.1 (i.e. all peaks with an m/z smaller than 0.1 are aggregated into -one binned peak. +one binned peak. Below, we explicitly set `zero.rm = FALSE` to retain all bins +generated by the function, including those with an intensity of zero. ```{r} -sps_bin <- Spectra::bin(sps, binSize = 0.1) +sps_bin <- Spectra::bin(sps, binSize = 0.1, zero.rm = FALSE) ``` All spectra will now have the same number of m/z values.