Skip to content

Commit

Permalink
Merge pull request #343 from rformassspectrometry/phili
Browse files Browse the repository at this point in the history
Addition of cbind2() to append multiple spectra variables to the spectra data
  • Loading branch information
jorainer authored Dec 9, 2024
2 parents 0deee7b + 0d53e26 commit d01763f
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 9 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: Spectra
Title: Spectra Infrastructure for Mass Spectrometry Data
Version: 1.17.1
Version: 1.17.2
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
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ exportMethods(backendParallelFactor)
exportMethods(backendRequiredSpectraVariables)
exportMethods(bin)
exportMethods(c)
exportMethods(cbind2)
exportMethods(centroided)
exportMethods(collisionEnergy)
exportMethods(combinePeaks)
Expand Down Expand Up @@ -309,4 +310,5 @@ importMethodsFrom(S4Vectors,extractROWS)
importMethodsFrom(S4Vectors,isEmpty)
importMethodsFrom(S4Vectors,lapply)
importMethodsFrom(S4Vectors,split)
importMethodsFrom(methods,cbind2)
importMethodsFrom(methods,show)
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Spectra 1.17

## Change in 1.17.2

- Add `cbind2()` method to easily add multiple `spectraVariables` and their
content to the `spectraData` of a `Spectra` object.
See also [issue #342](https://github.com/rformassspectrometry/Spectra/issues/342)

## Changes in 1.17.1

- Refactor `containsMz()` to support chunk-wise processing.
Expand Down
40 changes: 37 additions & 3 deletions R/MsBackend.R
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,15 @@
#' @param value replacement value for `<-` methods. See individual
#' method description or expected data type.
#'
#' @param values for `filterValues()`: A `numeric` vector that define the
#' @param values For `filterValues()`: A `numeric` vector that define the
#' values to filter the `object`. `values` needs to be of same length than
#' parameter `spectraVariables` and in the same order.
#'
#' @param y For `cbind2()`: A `data.frame` or `DataFrame` with the
#' spectra variables to be added to the backend. Need to be of the same
#' length as the number of spectra in the backend. The number of rows and
#' their order has to match the number of spectra and their order in x.
#'
#' @param x Object extending `MsBackend`.
#'
#' @param ... Additional arguments.
Expand Down Expand Up @@ -313,6 +318,12 @@
#' `dropNaSpectraVariables()` might still show columns containing `NA` values
#' for *core* spectra variables.
#'
#' - `cbind2()`: allows to appends multiple spectra variables to the backend at
#' once. The `Spectra` and the values for the new spectra variables have to
#' be in a matching order. Replacing existing spectra variables is not
#' supported through this function. For a more controlled way of adding
#' spectra variables, the `joinSpectraData()` should be used.
#'
#' - `centroided()`, `centroided<-`: gets or sets the centroiding
#' information of the spectra. `centroided()` returns a `logical`
#' vector of length equal to the number of spectra with `TRUE` if a
Expand Down Expand Up @@ -1022,6 +1033,29 @@ setMethod("peaksVariables", "MsBackend", function(object) {
c("mz", "intensity")
})


setClassUnion("dataframeOrDataFrameOrmatrix", c("data.frame", "DataFrame", "matrix"))
#' @exportMethod cbind2
#'
#' @importMethodsFrom methods cbind2
#'
#' @rdname MsBackend
setMethod("cbind2", signature = c("MsBackend", "dataframeOrDataFrameOrmatrix"),
function(x, y = data.frame(), ...) {
if (is(y, "matrix"))
y <- as.data.frame(y)
if (any(colnames(spectraData(x)) %in% colnames(y)))
stop("spectra variables in 'y' are already present in 'x' ",
"replacing them is not allowed")
if (nrow(y) != length(x))
stop("Number of row in 'y' does not match the number of spectra in 'x'")
for (i in colnames(y)) {
x[[i]] <- y[, i]
}
x
})


#' @exportMethod centroided
#'
#' @aliases centroided<-,MsBackend-method
Expand Down Expand Up @@ -1344,7 +1378,7 @@ setMethod("filterRanges", "MsBackend",
return(object)
if (!is.numeric(ranges))
stop("filterRanges only support filtering for numerical ",
"'spectraVariables'")
"'spectraVariables'")
match <- match.arg(match)
if (is.character(spectraVariables)){
if(!all(spectraVariables %in% spectraVariables(object)))
Expand All @@ -1354,7 +1388,7 @@ setMethod("filterRanges", "MsBackend",
"function to list possible values.")
} else
stop("The 'spectraVariables' parameter needs to be of type ",
"'character'.")
"'character'.")
if (length(spectraVariables) != length(ranges) / 2)
stop("Length of 'ranges' needs to be twice the length of ",
"the parameter 'spectraVariables' and define the lower ",
Expand Down
19 changes: 19 additions & 0 deletions R/MsBackendDataFrame.R
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,25 @@ setMethod("[", "MsBackendDataFrame", function(x, i, j, ..., drop = FALSE) {
.subset_backend_data_frame(x, i)
})

#' @importMethodsFrom methods cbind2
#'
#' @rdname hidden_aliases
setMethod("cbind2", signature = c("MsBackendDataFrame",
"dataframeOrDataFrameOrmatrix"),
function(x, y = data.frame(), ...) {
if (is(y, "matrix"))
y <- as.data.frame(y)
if (any(colnames(spectraData(x)) %in% colnames(y)))
stop("spectra variables in 'y' are already present in 'x' ",
"replacing them is not allowed")
if (nrow(y) != length(x))
stop("Number of row in 'y' does not match the number of ",
"spectra in 'x'")
x@spectraData <- cbind(x@spectraData, y)
validObject(x)
x
})

#' @rdname hidden_aliases
setMethod("split", "MsBackendDataFrame", function(x, f, drop = FALSE, ...) {
if (!is.factor(f))
Expand Down
20 changes: 20 additions & 0 deletions R/MsBackendMemory.R
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,26 @@ setMethod("[", "MsBackendMemory", function(x, i, j, ..., drop = FALSE) {
.df_subset(x, i)
})

#' @importMethodsFrom methods cbind2
#'
#' @rdname hidden_aliases
setMethod("cbind2", signature = c("MsBackendMemory",
"dataframeOrDataFrameOrmatrix"),
function(x, y = data.frame(), ...) {
if (is(y, "matrix"))
y <- as.data.frame(y)
if (any(colnames(spectraData(x)) %in% colnames(y)))
stop("spectra variables in 'y' are already present in 'x' ",
"replacing them is not allowed")

if (nrow(y) != length(x))
stop("Number of row in'y' does not match the number of ",
"spectra in 'x'")
x@spectraData <- cbind(x@spectraData, y)
validObject(x)
x
})

#' @rdname hidden_aliases
setMethod("split", "MsBackendMemory", function(x, f, drop = FALSE, ...) {
if (!is.factor(f))
Expand Down
31 changes: 30 additions & 1 deletion R/Spectra.R
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,7 @@ setReplaceMethod("[[", "Spectra", function(x, i, j, ..., value) {
#' @aliases combineSpectra
#' @aliases split
#' @aliases joinSpectraData
#' @aliases cbind2
#'
#' @description
#'
Expand All @@ -1463,6 +1464,16 @@ setReplaceMethod("[[", "Spectra", function(x, i, j, ..., value) {
#' function and to eventually (if needed) apply the processing queue using
#' the [applyProcessing()] function.
#'
#' - `cbind2()`: Appends multiple spectra variables from a `data.frame`,
#' `DataFrame` or `matrix` to the `Spectra` object at once. It does so
#' *blindly* (e.g. do not check rownames compatibility) and is therefore at
#' the risk of the user. The function also does not allow to replace existing
#' spectra variables. For a more controlled way of adding spectra
#' variables, the `joinSpectraData()` should be used. It will return a
#' `Spectra` object with the appended spectra variables. `cbind2()` does
#' check however that the number of rows of the `data.frame` or `DataFrame`
#' matches the number of spectra in the `Spectra` object.
#'
#' - `combineSpectra()`: combines sets of spectra (defined with parameter `f`)
#' into a single spectrum per set aggregating their MS data (i.e. their
#' *peaks data* matrices with the *m/z* and intensity values of their
Expand Down Expand Up @@ -1507,6 +1518,8 @@ setReplaceMethod("[[", "Spectra", function(x, i, j, ..., value) {
#' should be explored and ideally be removed using for
#' `QFeatures::reduceDataFrame()`, `PMS::reducePSMs()` or similar
#' functions.
#' For a more general function that allows to append `data.frame`,
#' `DataFrame` and `matrix` see `cbind2()`.
#'
#' - `split()`: splits the `Spectra` object based on parameter `f` into a `list`
#' of `Spectra` objects.
Expand Down Expand Up @@ -1543,7 +1556,10 @@ setReplaceMethod("[[", "Spectra", function(x, i, j, ..., value) {
#'
#' @param x A `Spectra` object.
#'
#' @param y A `DataFrame` with the spectra variables to join/add.
#' @param y For `joinSpectraData()`: `DataFrame` with the spectra variables
#' to join/add. For `cbind2()`: a `data.frame`, `DataFrame` or
#' `matrix`. The number of rows and their order has to match the
#' number of spectra in `x`, respectively their order.
#'
#' @param ... Additional arguments.
#'
Expand Down Expand Up @@ -1660,6 +1676,10 @@ setReplaceMethod("[[", "Spectra", function(x, i, j, ..., value) {
#'
#' spectraVariables(sciex2)
#' spectraData(sciex2)[1:13, c("spectrumId", "var1", "var2")]
#'
#' ## Append new spectra variables with cbind2()
#' df <- data.frame(cola = seq_len(length(sciex1)), colb = "b")
#' data_append <- cbind2(sciex1, df)
NULL

#' @rdname combineSpectra
Expand All @@ -1669,6 +1689,15 @@ setMethod("c", "Spectra", function(x, ...) {
.concatenate_spectra(unname(list(unname(x), ...)))
})

#' @rdname combineSpectra
#'
#' @export
setMethod("cbind2", signature(x = "Spectra",
y = "dataframeOrDataFrameOrmatrix"),
function(x, y, ...) {
x@backend <- cbind2(x@backend, y, ...)
})

#' @rdname combineSpectra
setMethod("split", "Spectra", function(x, f, drop = FALSE, ...) {
bcknds <- split(x@backend, f, ...)
Expand Down
22 changes: 22 additions & 0 deletions inst/test_backends/test_MsBackend/test_spectra_subsetting.R
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ test_that("[", {
expect_equal(res, be[which(l)])
})

test_that("cbind2 works", {
seql <- length(be)
df <- data.frame(cola = seq_len(seql), colb = "b", colz = "z")
res <- cbind2(be, df)
expect_true(validObject(res))
expect_equal(ncol(spectraData(res)), length(spectraVariables(be)) + 3)
expect_equal(res$cola, seq_len(seql))
expect_equal(res$colb, rep("b", seql))
expect_equal(res$colz, rep("z", seql))
df2 <- data.frame(cola = 3:6, colb = "b", colz = "z")
expect_error(cbind2(be, df2), "does not match")
## with matrix
m <- matrix(1:seql, ncol = 1, dimnames = list(NULL, "m"))
res <- cbind2(be, m)
expect_true(validObject(res))
expect_equal(ncol(spectraData(res)), length(spectraVariables(be)) + 1)
expect_equal(res$m, 1:seql)
## no replacing
expect_error(cbind2(be, data.frame(scanIndex = 1:seql)),
"are already present")
})

#' extractByIndex. Uses [ if not implemented
test_that("extractByIndex", {
i <- sample(seq_along(be), floor(length(be) / 2))
Expand Down
19 changes: 16 additions & 3 deletions man/MsBackend.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 23 additions & 1 deletion man/combineSpectra.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d01763f

Please sign in to comment.