From 53346fa6ddae91a305c8b2b9b938843813c6a267 Mon Sep 17 00:00:00 2001 From: Philippine Louail Date: Thu, 21 Mar 2024 17:08:43 +0100 Subject: [PATCH] Addition loadResults --- NAMESPACE | 4 +- R/AllGenerics.R | 58 ++++++++++ R/PlainTextParam.R | 154 +++++++++++++++++++++++---- R/RDataParam.R | 56 ++++++---- man/PlainTextParam.Rd | 31 ++++-- man/RDataParam.Rd | 27 +++-- man/loadResults.Rd | 61 +++++++++++ tests/testthat/test_PlainTextParam.R | 13 +++ 8 files changed, 338 insertions(+), 66 deletions(-) create mode 100644 man/loadResults.Rd diff --git a/NAMESPACE b/NAMESPACE index 1592c843d..51962fc2b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -589,12 +589,12 @@ exportMethods("filterMzRange") exportMethods("fromFile") exportMethods("fileNames") -## saving xcms objects things +## saving/loading xcms objects things importFrom("jsonlite", "serializeJSON", "write_json", "unserializeJSON", "read_json") export("RDataParam") export("PlainTextParam") -exportMethods("storeResults") +exportMethods("storeResults", "loadResults") ## filtering features things importFrom("MetaboCoreUtils", "rowRsd", "rowDratio", "rowPercentMissing", diff --git a/R/AllGenerics.R b/R/AllGenerics.R index 2d69b37bf..fb2ad2399 100644 --- a/R/AllGenerics.R +++ b/R/AllGenerics.R @@ -1464,6 +1464,64 @@ setGeneric("kNN<-", function(object, value) standardGeneric("kNN<-")) ## L setGeneric("levelplot", function(x, data, ...) standardGeneric("levelplot")) +#' @title Import various file format as XcmsExperiment object +#' +#' @description +#' +#' The `loadResults` function allows to import and create an `XcmsExperiment` +#' object from a file. Multiple formats for importing are available and can be +#' defined by the `param` argument. +#' +#' Supported `param` objects are: +#' +#' - [`RDataParam`]: Import an .RData format file.TBD +#' +#' - [`PlainTextParam`]: Import/create an `XcmsExperiment` object from a folder +#' of text files. +#' +#' - `MzTabParam`: Load a MzTab-m file (to be defined). +#' +#' For specific examples, see the help pages of the individual parameter classes +#' listed above. +#' +#' @param file `MsExperiment` or `XcmsExperiment` The data object that needs +#' to be saved. +#' +#' @param param The parameter object selecting and configuring the format for +#' saving. It can be one of the following classes: [`RDataParam`], +#' [`PlainTextParam`], or `MzTabParam`. +#' +#' @param ... Optional parameters. +#' +#' @note +#' The same `param` object can be used to import as it was used for export with +#' the `storeResults()` function. +#' +#' @name loadResults +#' +#' @author Philippine Louail +#' +#' @examples +#' ## Load a test data set with detected peaks +#' faahko_sub <- loadXcmsData("faahko_sub2") +#' +#' ## Save as RData +#' param <- RDataParam(fileName = "example_xcms_object") +#' storeResults(object = faahko_sub, param = param) +#' +#' ## Load this saved dataset +#' xcmse <- loadResults(param = param) +#' +#' ## Save as a collection of plain text files +#' pth = file.path(tempdir(), "test") +#' param <- PlainTextParam(path = pth) +#' storeResults(object = faahko_sub, param = param) +#' +#' ## Load this saved dataset +#' faahko_load <- loadResults(param = param) +#' +#' @md +setGeneric("loadResults", function(param, ...) standardGeneric("loadResults")) setGeneric("localAlignment", function(object) standardGeneric("localAlignment")) setGeneric("localAlignment<-", function(object, value) standardGeneric("localAlignment<-")) setGeneric("loadRaw", function(object, ...) standardGeneric("loadRaw")) diff --git a/R/PlainTextParam.R b/R/PlainTextParam.R index 73e7c33d8..f8b13f9c8 100644 --- a/R/PlainTextParam.R +++ b/R/PlainTextParam.R @@ -1,20 +1,21 @@ -#' @title Store contents of `MsExperiment` and `XcmsExperiment` objects as -#' plain text files +#' @title Store/load contents of `MsExperiment` and `XcmsExperiment` objects +#' as/from plain text files #' #' @name PlainTextParam #' #' @export #' -#' @family xcms result export formats. +#' @family xcms result export and import formats. #' #' @description -#' The `PlainTextParam` class and method enable users to save `MsExperiment` or -#' `XcmsExperiment` objects as collections of plain text files in a specified -#' folder. Note that, while for all xcms results within the `XcmsExperiment` can +#' The `PlainTextParam` class and method enable users to save/load an +#' `MsExperiment` or `XcmsExperiment` object as a collections of plain text +#' files in/from a specified folder. +#' Note that, while for all xcms results within the `XcmsExperiment` can #' and will be exported, the full raw MS data (of the object's `Spectra` object) #' will currently not be exported in plain text format. For `Spectra` using the #' [MsBackendMzR()] backend, the names of the raw data files will however be -#' exported (which enables to *restore* the full `Spectra` respectively +#' exported (which enables to *load* the full `Spectra` respectively #' `MsExperiment` objects). #' #' For an `MsExperiment` object, the exported files include: @@ -49,12 +50,14 @@ #' with their names. #' #' This `param` class and method are part of the possible dispatch of the -#' generic function `storeResults`. The folder will be created by calling +#' generic functions `storeResults()` and `loadResults()`. +#' The folder defined in the `path` parameter will be created by calling #' `storeResults`. If the folder already exists, previous exports in that #' folder might get overwritten. #' -#' @param path for `PlainTextParam` `character(1)`, defining where the files are -#' going to be stored. The default will be `tempdir()`. +#' @param path for `PlainTextParam` `character(1)`, defining where the files +#' are going to be stored/ should be loaded from. The default will be +#' `tempdir()`. #' #' @inheritParams storeResults #' @@ -94,6 +97,9 @@ #' ## Save as a collection of plain text files #' storeResults(object = faahko_sub, param = param) #' +#' ## Load this saved dataset +#' faahko_load <- loadResults(param = param) +#' NULL #' @noRd @@ -116,17 +122,41 @@ PlainTextParam <- function(path = tempdir()) { new("PlainTextParam", path = path) } - +### methods #' @rdname PlainTextParam setMethod("storeResults", signature(object = "MsExperiment", param = "PlainTextParam"), function(object, param){ - dir.create(path = param@path, recursive = TRUE, showWarnings = TRUE) + dir.create(path = param@path, + recursive = TRUE, + showWarnings = TRUE) .store_msexperiment(x = object, path = param@path) } ) +#' @rdname PlainTextParam +setMethod("storeResults", + signature(object = "XcmsExperiment", + param = "PlainTextParam"), + function(object, param){ + callNextMethod() + .store_xcmsexperiment(x = object, path = param@path) + } +) + +#' @rdname PlainTextParam +setMethod("loadResults", + signature(param = "PlainTextParam"), + function(param){ + res <- .load_msexperiment(path = param@path) + fl <- file.path(path, "chrom_peaks.txt") + if (file.exists(fl)) + res <- .load_xcmsexperiment(res, path = param@path) + validObject(res) + res + } +) #' @noRd .store_msexperiment <- function(x, path = tempdir()) { @@ -136,12 +166,34 @@ setMethod("storeResults", .export_spectra_processing_queue(spectra(x), path = path) } +#' @noRd +.load_msexperiment <- function(path = character()) { + fl <- file.path(path, "sample_data.txt") + if (file.exists(fl)) + sd <- .import_sample_data(fl) + else stop("No \"sample_data.txt\" file found in ", path) + fl <- file.path(path, "spectra_files.txt") + if (file.exists(fl)){ + sf <- .import_spectra_files(fl) + res <- readMsExperiment(spectraFiles = sf, sampleData = sd) + fl <- file.path(path, "spectra_processing_queue.json") + if (file.exists(fl)) + res <- .import_processing_queue(res, fl) + } else stop("No \"spectra_files.txt\" file found in ", path, "Spectra ", + "data will not be restored") +} + #' Sample data #' @noRd .export_sample_data <- function(x, file = tempfile()) { write.table(x, file = file) } +#' @noRd +.import_sample_data <- function(file = character()) { + read.table(file) +} + #' Spectra file #' @noRd .export_spectra_files <- function(x, path = character()) { @@ -156,8 +208,13 @@ setMethod("storeResults", } } +#' @noRd +.import_spectra_files <- function(file = character()) { + as.character(read.table(file)[, 1L]) +} + #' Processing queue -#' @param x `Spectra` +#' @param x `Spectra` (for export) `MsExperiment` (for import) #' #' @noRd .export_spectra_processing_queue <- function(x, path = character()) { @@ -167,16 +224,11 @@ setMethod("storeResults", file.path(path, "spectra_processing_queue.json")) } - -#' @rdname PlainTextParam -setMethod("storeResults", - signature(object = "XcmsExperiment", - param = "PlainTextParam"), - function(object, param){ - callNextMethod() - .store_xcmsexperiment(x = object, path = param@path) - } -) +#' @noRd +.import_spectra_processing_queue <- function(x, file = character()) { + x@spectra@processingQueue <- unserializeJSON(read_json(file)[[1L]]) + x +} #' @noRd .store_xcmsexperiment <- function(x, path = tempdir()) { @@ -189,6 +241,22 @@ setMethod("storeResults", .export_features(x, path) } +#' @noRd +.load_xcmsexperiment <- function(x, path = character()){ + res <- as(res, "XcmsExperiment") + res <- .import_chrom_peaks(res, path) + fl <- file.path(path, "process_history.json") + if (file.exists(fl)) + res <- .import_process_history(res, fl) + else stop("No \"process_history.json\" file found in ", path) + fl <- file.path(path, "rtime_adjusted.txt") + if (file.exists(fl)) + res <- .import_adjusted_rtime(res, fl) + fl <- file.path(path, "feature_definitions.txt") + if (file.exists(fl)) + res <- .import_features(res, path) +} + #' Processing history #' @noRd .export_process_history <- function(x, path = character()) { @@ -196,6 +264,13 @@ setMethod("storeResults", write_json(serializeJSON(ph), file.path(path, "process_history.json")) } +#' @noRd +.import_process_history <- function(x, file = character()) { + ph <- unserializeJSON(read_json(file)[[1L]]) + x@processHistory <- ph + x +} + #' Chromatographic peaks #' @noRd .export_chrom_peaks <- function(x, path = character()) { @@ -204,6 +279,19 @@ setMethod("storeResults", file = file.path(path, "chrom_peak_data.txt")) } +#' @noRd +.import_chrom_peaks <- function(x, path = character()) { + f <- file.path(path, "chrom_peaks.txt") + pk <- as.matrix(read.table(f)) + f <- file.path(path, "chrom_peak_data.txt") + if (!file.exists(f)) + stop("No \"chrom_peak_data.txt\" file found in ", path) + pkd <- read.table(f) + x@chromPeaks <- pk + x@chromPeakData <- pkd + x +} + #' Retention times #' @noRd .export_adjusted_rtime <- function(x, path = character()) { @@ -211,6 +299,13 @@ setMethod("storeResults", row.names = FALSE, col.names = FALSE) } +#' @noRd +.import_adjusted_rtime <- function(x, file = character()) { + rts <- read.table(file)[, 1L] + x@spectra$rtime_adjusted <- as.numeric(rts) + x +} + #' Features #' @noRd .export_features <- function(x, path = character()) { @@ -222,3 +317,16 @@ setMethod("storeResults", write.table(fts, file = file.path(path, "feature_definitions.txt")) write.table(pkidx, file = file.path(path, "feature_peak_index.txt")) } + +#' @noRd +.import_features <- function(x, path = character()) { + f <- file.path(path, "feature_definitions.txt") + fts <- read.table(f) + f <- file.path(path, "feature_peak_index.txt") + if (!file.exists(f)) + stop("No \"feature_peak_index.txt\" file found in ", path) + pkidx <- read.table(f) + fts$peakidx <- unname(split(pkidx$peak_index, pkidx$feature_index)) + x@featureDefinitions <- fts + x +} diff --git a/R/RDataParam.R b/R/RDataParam.R index 59a7db860..eaaa49b2b 100644 --- a/R/RDataParam.R +++ b/R/RDataParam.R @@ -1,24 +1,27 @@ -#' @title Store `XcmsExperiment` object as .RData file +#' @title Store/Load an `XcmsExperiment` object as/from .RData file #' #' @name RDataParam #' #' @export -#' -#' @family xcms result export formats. -#' +#' +#' @family xcms result export and import formats. +#' #' @description -#' The `RDataParam` class and method allow users to save an `XcmsExperiment` -#' object as an .RData file with a chosen filename. The object gets exported -#' using [`save()`] function. This `param` class and method are part of the -#' possible dispatch of the generic function `storeResults`. -#' +#' The `RDataParam` class and method allow users to save or load an +#' `XcmsExperiment` object as/from an .RData file with a defined filename. The +#' object gets exported using [`save()`] function and imported using the +#' [`load()`] function. This `param` class and method are part of the +#' possible dispatch of the generic functions `storeResults()` and +#' `loadResults()`. +#' #' @param fileName for `RDataParam` `character(1)`, defining the file name. The #' default will be `tempfile()`. -#' +#' #' @inheritParams storeResults -#' +#' #' @return for `RDataParam`: a `RDataParam` class. `storeResults` does not -#' return anything but saves the object to a RData file. +#' return anything but saves the object to a RData file. `loadResults` returns +#' an object of class `XcmsExperiment` #' #' @author Philippine Louail #' @@ -26,24 +29,27 @@ #' #' ## Load a test data set with detected peaks #' faahko_sub <- loadXcmsData("faahko_sub2") -#' -#' ## Define param +#' +#' ## Define param #' param <- RDataParam(fileName = "example_xcms_object") -#' +#' #' ## Save as RData #' storeResults(object = faahko_sub, param = param) -#' +#' +#' ## Load this saved dataset +#' xcmse <- loadResults(param = param) +#' NULL #' @noRd setClass("RDataParam", - slots = c(fileName = "character"), + slots = c(fileName = "character"), contains = "Param", prototype = prototype( fileName = character()), validity = function(object) { msg <- NULL - if (length(object@fileName) != 1) + if (length(object@fileName) != 1) msg <- c("'fileName' has to be a character string of length 1") msg }) @@ -54,13 +60,21 @@ setClass("RDataParam", RDataParam <- function(fileName = tempfile()) { new("RDataParam", fileName = fileName) } - + #' @rdname RDataParam setMethod("storeResults", - signature(object = "XcmsExperiment", - param = "RDataParam"), + signature(object = "XcmsExperiment", + param = "RDataParam"), function(object, param){ save(object, file = param@fileName) } ) +#' @rdname RDataParam +setMethod("loadResults", + signature(param = "RDataParam"), + function(param){ + load(file = param@fileName) + } +) + diff --git a/man/PlainTextParam.Rd b/man/PlainTextParam.Rd index 8bd806486..1613e5c31 100644 --- a/man/PlainTextParam.Rd +++ b/man/PlainTextParam.Rd @@ -4,18 +4,22 @@ \alias{PlainTextParam} \alias{storeResults,MsExperiment,PlainTextParam-method} \alias{storeResults,XcmsExperiment,PlainTextParam-method} -\title{Store contents of `MsExperiment` and `XcmsExperiment` objects as -plain text files} +\alias{loadResults,PlainTextParam-method} +\title{Store/load contents of `MsExperiment` and `XcmsExperiment` objects +as/from plain text files} \usage{ PlainTextParam(path = tempdir()) \S4method{storeResults}{MsExperiment,PlainTextParam}(object, param) \S4method{storeResults}{XcmsExperiment,PlainTextParam}(object, param) + +\S4method{loadResults}{PlainTextParam}(param) } \arguments{ -\item{path}{for `PlainTextParam` `character(1)`, defining where the files are -going to be stored. The default will be `tempdir()`.} +\item{path}{for `PlainTextParam` `character(1)`, defining where the files +are going to be stored/ should be loaded from. The default will be +`tempdir()`.} \item{object}{\code{MsExperiment} or \code{XcmsExperiment} The data object that needs to be saved.} @@ -30,13 +34,14 @@ not return anything but saves the object to collections of different plain text files to a folder. } \description{ -The `PlainTextParam` class and method enable users to save `MsExperiment` or -`XcmsExperiment` objects as collections of plain text files in a specified -folder. Note that, while for all xcms results within the `XcmsExperiment` can +The `PlainTextParam` class and method enable users to save/load an +`MsExperiment` or `XcmsExperiment` object as a collections of plain text +files in/from a specified folder. +Note that, while for all xcms results within the `XcmsExperiment` can and will be exported, the full raw MS data (of the object's `Spectra` object) will currently not be exported in plain text format. For `Spectra` using the [MsBackendMzR()] backend, the names of the raw data files will however be -exported (which enables to *restore* the full `Spectra` respectively +exported (which enables to *load* the full `Spectra` respectively `MsExperiment` objects). For an `MsExperiment` object, the exported files include: @@ -71,7 +76,8 @@ in the text file named *rtime_adjusted.txt*. with their names. This `param` class and method are part of the possible dispatch of the -generic function `storeResults`. The folder will be created by calling +generic functions `storeResults()` and `loadResults()`. +The folder defined in the `path` parameter will be created by calling `storeResults`. If the folder already exists, previous exports in that folder might get overwritten. } @@ -103,12 +109,15 @@ param <- PlainTextParam(path = pth) ## Save as a collection of plain text files storeResults(object = faahko_sub, param = param) +## Load this saved dataset +faahko_load <- loadResults(param = param) + } \seealso{ -Other xcms result export formats.: +Other xcms result export and import formats.: \code{\link{RDataParam}} } \author{ Philippine Louail, Johannes Rainer. } -\concept{xcms result export formats.} +\concept{xcms result export and import formats.} diff --git a/man/RDataParam.Rd b/man/RDataParam.Rd index 617c3dc93..a3830f0b8 100644 --- a/man/RDataParam.Rd +++ b/man/RDataParam.Rd @@ -3,11 +3,14 @@ \name{RDataParam} \alias{RDataParam} \alias{storeResults,XcmsExperiment,RDataParam-method} -\title{Store `XcmsExperiment` object as .RData file} +\alias{loadResults,RDataParam-method} +\title{Store/Load an `XcmsExperiment` object as/from .RData file} \usage{ RDataParam(fileName = tempfile()) \S4method{storeResults}{XcmsExperiment,RDataParam}(object, param) + +\S4method{loadResults}{RDataParam}(param) } \arguments{ \item{fileName}{for `RDataParam` `character(1)`, defining the file name. The @@ -22,31 +25,37 @@ saving. It can be one of the following classes: \code{\link{RDataParam}}, } \value{ for `RDataParam`: a `RDataParam` class. `storeResults` does not -return anything but saves the object to a RData file. +return anything but saves the object to a RData file. `loadResults` returns +an object of class `XcmsExperiment` } \description{ -The `RDataParam` class and method allow users to save an `XcmsExperiment` -object as an .RData file with a chosen filename. The object gets exported -using [`save()`] function. This `param` class and method are part of the -possible dispatch of the generic function `storeResults`. +The `RDataParam` class and method allow users to save or load an +`XcmsExperiment` object as/from an .RData file with a defined filename. The +object gets exported using [`save()`] function and imported using the +[`load()`] function. This `param` class and method are part of the +possible dispatch of the generic functions `storeResults()` and +`loadResults()`. } \examples{ ## Load a test data set with detected peaks faahko_sub <- loadXcmsData("faahko_sub2") -## Define param +## Define param param <- RDataParam(fileName = "example_xcms_object") ## Save as RData storeResults(object = faahko_sub, param = param) +## Load this saved dataset +xcmse <- loadResults(param = param) + } \seealso{ -Other xcms result export formats.: +Other xcms result export and import formats.: \code{\link{PlainTextParam}} } \author{ Philippine Louail } -\concept{xcms result export formats.} +\concept{xcms result export and import formats.} diff --git a/man/loadResults.Rd b/man/loadResults.Rd new file mode 100644 index 000000000..eea98003c --- /dev/null +++ b/man/loadResults.Rd @@ -0,0 +1,61 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/AllGenerics.R +\name{loadResults} +\alias{loadResults} +\title{Import various file format as XcmsExperiment object} +\usage{ +loadResults(param, ...) +} +\arguments{ +\item{param}{The parameter object selecting and configuring the format for +saving. It can be one of the following classes: \code{\link{RDataParam}}, +\code{\link{PlainTextParam}}, or \code{MzTabParam}.} + +\item{...}{Optional parameters.} + +\item{file}{\code{MsExperiment} or \code{XcmsExperiment} The data object that needs +to be saved.} +} +\description{ +The \code{loadResults} function allows to import and create an \code{XcmsExperiment} +object from a file. Multiple formats for importing are available and can be +defined by the \code{param} argument. + +Supported \code{param} objects are: +\itemize{ +\item \code{\link{RDataParam}}: Import an .RData format file.TBD +\item \code{\link{PlainTextParam}}: Import/create an \code{XcmsExperiment} object from a folder +of text files. +\item \code{MzTabParam}: Load a MzTab-m file (to be defined). +} + +For specific examples, see the help pages of the individual parameter classes +listed above. +} +\note{ +The same \code{param} object can be used to import as it was used for export with +the \code{storeResults()} function. +} +\examples{ +## Load a test data set with detected peaks +faahko_sub <- loadXcmsData("faahko_sub2") + +## Save as RData +param <- RDataParam(fileName = "example_xcms_object") +storeResults(object = faahko_sub, param = param) + +## Load this saved dataset +xcmse <- loadResults(param = param) + +## Save as a collection of plain text files +pth = file.path(tempdir(), "test") +param <- PlainTextParam(path = pth) +storeResults(object = faahko_sub, param = param) + +## Load this saved dataset +faahko_load <- loadResults(param = param) + +} +\author{ +Philippine Louail +} diff --git a/tests/testthat/test_PlainTextParam.R b/tests/testthat/test_PlainTextParam.R index caaffe1cb..f517d8084 100644 --- a/tests/testthat/test_PlainTextParam.R +++ b/tests/testthat/test_PlainTextParam.R @@ -32,3 +32,16 @@ test_that("storeResults,PlainTextParam,XcmsExperiment works", { expect_true(file.exists(file.path(param@path, "feature_definitions.txt"))) expect_true(file.exists(file.path(param@path, "feature_peak_index.txt"))) }) + +test_that("loadResults, PlainTextParam works", { + pth = file.path(tempdir(), "test") + param <- PlainTextParam(path = pth) + storeResults(xmse_full, param = param) + load_xmse <- loadResults(param) + expect_true(inherits(load_xmse, "XcmsExperiment")) + expect_equal(xmse_full, load_xmse) + expect_equal(processHistory(xmse_full), processHistory(load_xmse)) + expect_equal(xmse_full@featureDefinitions, + load_xmse@featureDefinitions) + expect_equal(adjustedRtime(xmse_full), adjustedRtime(load_xmse)) + })