diff --git a/NAMESPACE b/NAMESPACE index 0061bdc70..800ab341e 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -447,6 +447,7 @@ export("CentWaveParam", "MassifquantParam", "MSWParam", "CentWavePredIsoParam", + "IMCentWaveParam", "PeakDensityParam", "MzClustParam", "NearestPeaksParam", diff --git a/R/AllGenerics.R b/R/AllGenerics.R index 0103bc603..18bca35cb 100644 --- a/R/AllGenerics.R +++ b/R/AllGenerics.R @@ -255,6 +255,8 @@ setGeneric("baseValue", function(object, ...) standardGeneric("baseValue")) setGeneric("baseValue<-", function(object, value) standardGeneric("baseValue<-")) setGeneric("binSize", function(object, ...) standardGeneric("binSize")) setGeneric("binSize<-", function(object, value) standardGeneric("binSize<-")) +setGeneric("binWidthIM", function(object, ...) standardGeneric("binWidthIM")) +setGeneric("binWidthIM<-", function(object, value) standardGeneric("binWidthIM<-")) setGeneric("bw", function(object) standardGeneric("bw")) setGeneric("bw<-", function(object, value) standardGeneric("bw<-")) @@ -736,6 +738,8 @@ setGeneric("plotTIC", function(object, ...) standardGeneric("plotTIC")) setGeneric("plotTree", function(object, ...) standardGeneric("plotTree")) setGeneric("ppm", function(object, ...) standardGeneric("ppm")) setGeneric("ppm<-", function(object, value) standardGeneric("ppm<-")) +setGeneric("ppmMerging", function(object, ...) standardGeneric("ppmMerging")) +setGeneric("ppmMerging<-", function(object, value) standardGeneric("ppmMerging<-")) setGeneric("prefilter", function(object, ...) standardGeneric("prefilter")) setGeneric("prefilter<-", function(object, value) standardGeneric("prefilter<-")) setGeneric("present", function(object, class, minfrac) standardGeneric("present")) diff --git a/R/DataClasses.R b/R/DataClasses.R index 810abc1e9..d13d35ab0 100644 --- a/R/DataClasses.R +++ b/R/DataClasses.R @@ -1298,6 +1298,82 @@ setClass("CentWavePredIsoParam", else TRUE }) +#### Ion mobility peak-picking classes #### + +setClass("IMParam", contains = "VIRTUAL") + +#' @title Centwave-based ion-mobility peak picking +#' +#' @aliases centWaveIonMobility +#' +#' @description Performs an extension of CentWave peak-picking on LC-IM-MS MS1 +#' data: first it joins all mobility scans into frames and performs .centWave_orig on +#' the summarized LC-MS-like data; then, from each peak, it calculates its mobilogram and +#' performs a second peak-picking on the IM dimension, resolving the peaks. +#' +#' @inheritParams findChromPeaks-centWave +#' +#' @param ppmMerging The maximum mass deviation allowed when grouping individual +#' IM scans into frames. Data points within \code{ppmMerging} ppm will be +#' summed up into a single value and the reported mz will be their weighted +#' average. +#' +#' @param binWidthIM The bin size used when calculating the mobilograms to resolve +#' the peaks into the ion-mobility dimension. Lower values will give better resolution +#' if the data allows it, but can also generate spurious peaks. +#' +#' @details See \code{\link{centWave}} for details on the centWave method. +#' +#' @family peak detection methods +#' +#' @author Roger Gine, Johannes Rainer +#' +#' @seealso The \code{\link{do_findChromPeaks_IM_centWave}} core +#' API function and \code{\link{CentWaveParam}} for the class the +#' \code{IMCentWaveParam} extends. +#' +#' @name findChromPeaks-centWaveIonMobility +NULL + +#' @description The \code{IMCentWaveParam} class allows to specify all +#' settings for +#' Instances should be created with the \code{IMCentWaveParam} +#' constructor. See also the documentation of the +#' \code{\link{CentWaveParam}} for all methods and arguments this class +#' inherits. +#' +#' @slot ppm,peakwidth,snthresh,prefilter,mzCenterFun,integrate,mzdiff,fitgauss,noise,verboseColumns,roiList,firstBaselineCheck,roiScales,ppmMerging,binWidthIM +#' See corresponding parameter above. +#' +#' @rdname findChromPeaks-centWaveIonMobility +setClass("IMCentWaveParam", + contains = c("IMParam", "CentWaveParam"), + slots = c( + ppmMerging = "numeric", + binWidthIM = "numeric" + + ), + prototype = prototype( + ppmMerging = 10, + binWidthIM = 0.02 + ), + validity = function(object){ + msg <- character() + if (length(object@ppmMerging) != 1 || + object@ppmMerging < 0) { + msg <- c(msg, + "'ppmMerging' should be a positive numeric of length 1") + } + if (length(object@binWidthIM) != 1 || + object@binWidthIM < 0) { + msg <- c(msg, + "'binWidthIM' should be a positive numeric of length 1") + } + if (length(msg)) + msg + else TRUE + }) + setClass("PeakDensityParam", slots = c(sampleGroups = "ANY", bw = "numeric", diff --git a/R/MsExperiment-functions.R b/R/MsExperiment-functions.R index db34ebb33..f5ef5d534 100644 --- a/R/MsExperiment-functions.R +++ b/R/MsExperiment-functions.R @@ -3,7 +3,8 @@ MatchedFilterParam = "do_findChromPeaks_matchedFilter", MassifquantParam = "do_findChromPeaks_massifquant", MSWParam = "do_findPeaks_MSW", - CentWavePredIsoParam = "do_findChromPeaks_centWaveWithPredIsoROIs") + CentWavePredIsoParam = "do_findChromPeaks_centWaveWithPredIsoROIs", + IMCentWaveParam = "do_findChromPeaks_IM_centWave") fun <- p2f[class(x)[1L]] if (is.na(fun)) stop("No peak detection function for parameter class ", class(x)[1L]) @@ -62,6 +63,11 @@ #' @noRd .mse_find_chrom_peaks_sample <- function(x, msLevel = 1L, param, ...) { x <- filterMsLevel(x, msLevel) + if(inherits(param, "IMParam")){ + if(!any(c("inv_ion_mobility") %in% Spectra::spectraVariables(x))) # Add any other column name needed + stop("Your Spectra object doesn't contain ion-mobility data") + return(do.call(.param_to_fun(param), args = append(list(x), as(param, "list")))) #Append to avoid concatenating spectra + } pkd <- Spectra::peaksData(x, columns = c("mz", "intensity"), BPPARAM = SerialParam()) vals_per_spect <- vapply(pkd, nrow, integer(1), USE.NAMES = FALSE) @@ -74,6 +80,9 @@ pkd <- do.call(rbind, pkd) if (!length(pkd)) return(NULL) # not returning matrix because of rbind + rts <- rtime(x) + if (is.unsorted(rts)) + stop("Spectra are not ordered by retention time", .call = FALSE) if (inherits(param, "CentWaveParam")) { centroided <- all(centroided(x)) if (is.na(centroided)) { @@ -83,9 +92,6 @@ " works best on data in centroid mode.") } } - rts <- rtime(x) - if (is.unsorted(rts)) - stop("Spectra are not ordered by retention time", .call = FALSE) do.call(.param_to_fun(param), args = c(list(mz = pkd[, 1L], int = pkd[, 2L], scantime = rts, valsPerSpect = vals_per_spect), as(param, "list"))) @@ -219,6 +225,19 @@ if (lx) f <- factor(x$.SAMPLE_IDX, levels = sidx) else f <- factor(integer(), levels = sidx) + + ## Ion mobility peak-picking dispatch point + if (inherits(param, "IMParam")){ + if (!any(c("inv_ion_mobility") %in% Spectra::spectraVariables(x))) # Add any other column name needed + stop("Spectra object does not seem to have ion-mobility data") + return ( + bplapply(split(x, f), function(spec){ + do.call(.param_to_fun(param), + args = append(list(spec), as(param, "list"))) #Append to avoid concatenating spectra + }, BPPARAM = BPPARAM) + ) + } + ## Check for random number of spectra if they are centroided. NOT all. if (inherits(param, "CentWaveParam")) { cntr <- all(centroided(x[sort(sample(seq_along(x), min(c(100, lx))))])) diff --git a/R/do_findChromPeaks-functions.R b/R/do_findChromPeaks-functions.R index b6d8d5e22..39357f5b9 100644 --- a/R/do_findChromPeaks-functions.R +++ b/R/do_findChromPeaks-functions.R @@ -2220,8 +2220,218 @@ do_findPeaks_MSW <- function(mz, int, snthresh = 3, peaklist } +############################################################ +## Ion-mobility peak picking +## +#' @title Core API for Centwave-based ion-mobility peak picking +#' @name do_findChromPeaks_IM_centWave +#' +#' @description Performs an extension of CentWave peak-picking on LC-IM-MS MS1 +#' data. First it joins all scans into frames and performs .centWave_orig on +#' the summarized LC-MS-like data. From each peak, it calculates its mobilogram and +#' performs a second peak-picking on the IM dimension, resolving the peaks. +#' +#' @inheritParams do_findChromPeaks_centWave +#' @inheritParams findChromPeaks-centWaveIonMobility +#' +#' @return A matrix, each row representing an identified peak, with columns: +#' \describe{ +#' \item{mz}{m/z value of the peak at the apex position.} +#' \item{mzmin}{Minimum m/z of the peak.} +#' \item{mzmax}{Maximum m/z of the peak.} +#' \item{rt}{Retention time value of the peak at the apex position.} +#' \item{rtmin}{Minimum retention time of the peak.} +#' \item{rtmax}{Maximum retention time of the peak.} +#' \item{im}{Ion mobility value of the peak at the apex position.} +#' \item{immin}{Minimum ion mobility value of the peak.} +#' \item{immax}{Maximum ion mobility value of the peak.} +#' \item{maxo}{Maximum intensity of the peak.} +#' \item{into}{Integrated (original) intensity of the peak.} +#' \item{intb}{Always \code{NA}.} +#' \item{sn}{Always \code{NA}} +#' } +#' +#' @family core peak detection functions +#' +#' @author Roger Gine, Johannes Rainer +#' +#' @importFrom Spectra peaksData rtime combineSpectra mz +do_findChromPeaks_IM_centWave <- function(spec, + ppm = 25, + peakwidth = c(20, 50), + snthresh = 10, + prefilter = c(3, 100), + mzCenterFun = "wMean", + integrate = 1, + mzdiff = -0.001, + fitgauss = FALSE, + noise = 0, + verboseColumns = FALSE, + roiList = list(), + firstBaselineCheck = TRUE, + roiScales = numeric(), + sleep = 0, + extendLengthMSW = FALSE, + ppmMerging = 10, + binWidthIM = 0.01 + ){ + + ## Merging all scans from the same frame to summarize across IM dimension + scans_summarized <- + Spectra::combineSpectra( + spec, + f = as.factor(spec$frameId), + intensityFun = base::sum, + weighted = TRUE, + ppm = ppmMerging + ) + Spectra::centroided(scans_summarized) <- TRUE + + ## 1D Peak-picking on summarized data + peaks <- .mse_find_chrom_peaks_sample(scans_summarized, + msLevel = 1L, + param = CentWaveParam(ppm = ppm, peakwidth = peakwidth, + snthresh = snthresh, prefilter = prefilter, + mzCenterFun = mzCenterFun, integrate = integrate, + mzdiff = mzdiff, fitgauss = fitgauss, noise = noise, + verboseColumns = verboseColumns, roiList = roiList, + firstBaselineCheck = firstBaselineCheck, + roiScales = roiScales, + extendLengthMSW = extendLengthMSW)) + if (!nrow(peaks)) return() + + #Correcting for the fact that combineSpectra combined close mz values + peaks[,"mzmin"] <- peaks[,"mzmin"] * (1 - ppmMerging * 1e-6) + peaks[,"mzmax"] <- peaks[,"mzmax"] * (1 + ppmMerging * 1e-6) + + ## 1D Peak-picking, for each individual peak, to resolve across the IM dimension + .do_resolve_IM_peaks_CWT(spec, peaks, binWidthIM) + +} +.do_resolve_IM_peaks_CWT <- function(spec, peaks, binWidthIM){ + ## Extract frame information + pdata <- peaksData(spec, columns = c("mz", "intensity")) + rt <- rtime(spec) + im <- spec$inv_ion_mobility + + ## Resolving peaks across IM dimension + resolved_peaks <- vector("list", nrow(peaks)) + for (i in seq_len(nrow(peaks))) { + current_peak <- peaks[i,] + mobilogram <- .extract_mobilogram(pdata, current_peak, rt, im, binWidthIM) + if (length(mobilogram) == 0) { + # warning(i, " mobilogram is empty") + next + } + + bounds <- .split_mobilogram(mobilogram) + new_peaks <- data.frame( + mz = current_peak["mz"], + mzmin = current_peak["mzmin"], + mzmax = current_peak["mzmax"], + rt = current_peak["rt"], + rtmin = current_peak["rtmin"], + rtmax = current_peak["rtmax"], + im = vapply(bounds, function(x) x[[2]], numeric(1)), + immin = vapply(bounds, function(x) x[[1]], numeric(1)), + immax = vapply(bounds, function(x) x[[3]], numeric(1)), + row.names = NULL + ) + resolved_peaks[[i]] <- new_peaks + } + + resolved_peaks <- do.call(rbind, resolved_peaks) + if(is.null(resolved_peaks) || !nrow(resolved_peaks)) return() + + ## Refine and calculate peak parameters + vals <- vector("list", nrow(resolved_peaks)) + for (i in seq(nrow(resolved_peaks))) { + peak <- unlist(resolved_peaks[i, , drop = TRUE]) + + ## Create a EIC for mz, rt and IM ranges + eic <- .extract_EIC_IM(peak, pdata, rt, im) + + if (nrow(eic) == 0 | all(eic[, 2] == 0)) + next + + ## Refine RT bounds + rts <- c(peak["rtmin"], peak["rtmax"]) + apx <- which.max(eic[, 2]) + apx_rt <- eic[apx, 1] + range <- xcms:::descendMin(eic[, 2], apx) + + eic <- eic[range[1]:range[2], , drop = FALSE] + + ## Calculate peak stats + vals[[i]] <- data.frame( + mz = peak["mz"], + mzmin = peak["mzmin"], + mzmax = peak["mzmax"], + rt = apx_rt, + rtmin = min(eic[, 1]), + rtmax = max(eic[, 1]), + im = peak["im"], + immin = peak["immin"], + immax = peak["immax"], + maxo = max(eic[, 2]), + into = sum(eic[, 2]), + intb = NA, + sn = NA + ) + } + resolved_peaks <- do.call(rbind, vals) + resolved_peaks <- + resolved_peaks[resolved_peaks$into > 0, ] #Remove empty peaks + + as.matrix(resolved_peaks) +} + +#' @importFrom MsCoreUtils between bin +.extract_mobilogram <- function(pdata, peak, rt, im, binWidthIM = 0.01){ + rtr <- c(peak[["rtmin"]], peak[["rtmax"]]) + mzr <- c(peak[["mzmin"]], peak[["mzmax"]]) + keep <- MsCoreUtils::between(rt, rtr) + if (length(keep) == 0) return() + ims <- im[keep] + ints <- vapply(pdata[keep], xcms:::.aggregate_intensities, + mzr = mzr, INTFUN = sum, na.rm = TRUE, numeric(1)) + if(all(ints == 0)) return() + mob <- MsCoreUtils::bin(x = ints[order(ims)], y = sort(ims), + size = binWidthIM, FUN = sum) + mob +} + + +.split_mobilogram <- function(mob){ + if(length(mob$x) == 0){return()} + vec <- mob$x + apex <- which(MsCoreUtils::localMaxima(vec, hws = 4)) + limits <- list() + for (i in seq_along(apex)){ + ranges <- descendMinTol(vec, startpos = c(apex[i], apex[i]), maxDescOutlier = 2) + limits[[i]] <- mob$mids[c(ranges[1], apex[i], ranges[2])] + } + limits <- limits[vapply(limits, function(x){!any(is.na(x))}, logical(1))] + limits +} + + +#' @importFrom dplyr between +.extract_EIC_IM <- function(peak, pdata, rt, im){ + rtr <- c(peak["rtmin"], peak["rtmax"]) + mzr <- c(peak["mzmin"], peak["mzmax"]) + imr <- c(peak["immin"], peak["immax"]) + + keep <- dplyr::between(rt, rtr[1], rtr[2]) & dplyr::between(im, imr[1], imr[2]) + rts <- rt[keep] + ints <- vapply(pdata[keep], xcms:::.aggregate_intensities, + mzr = mzr, INTFUN = sum, na.rm = TRUE, numeric(1)) + ints <- vapply(unique(rts), function(x){sum(ints[rts == x])}, numeric(1)) + + cbind(unique(rts), ints) +} ############################################################ diff --git a/R/functions-Params.R b/R/functions-Params.R index 24e1f7908..e429eba02 100644 --- a/R/functions-Params.R +++ b/R/functions-Params.R @@ -226,6 +226,33 @@ CentWavePredIsoParam <- function(ppm = 25, peakwidth = c(20, 50), snthresh = 10, mzIntervalExtension = mzIntervalExtension, polarity = polarity)) } + +#' @return The \code{IMCentWaveParam} function returns a +#' \code{IMCentWaveParam} class instance with all of the settings +#' specified for the centWave-based peak detection in chromatographic + +#' ion mobility data. +#' +#' @rdname findChromPeaks-centWaveIonMobility +#' +IMCentWaveParam <- function(ppm = 25, peakwidth = c(20, 50), snthresh = 10, + prefilter = c(3, 100), mzCenterFun = "wMean", + integrate = 1L, mzdiff = -0.001, fitgauss = FALSE, + noise = 0, verboseColumns = FALSE, roiList = list(), + firstBaselineCheck = TRUE, roiScales = numeric(), + extendLengthMSW = FALSE, ppmMerging = 10, + binWidthIM = 0.02) { + return(new("IMCentWaveParam", ppm = ppm, peakwidth = peakwidth, + snthresh = snthresh, prefilter = prefilter, + mzCenterFun = mzCenterFun, integrate = as.integer(integrate), + mzdiff = mzdiff, fitgauss = fitgauss, noise = noise, + verboseColumns = verboseColumns, roiList = roiList, + firstBaselineCheck = firstBaselineCheck, roiScales = roiScales, + extendLengthMSW = extendLengthMSW, ppmMerging = ppmMerging, + binWidthIM = binWidthIM)) +} + + + #' @rdname groupChromPeaks PeakDensityParam <- function(sampleGroups = numeric(), bw = 30, minFraction = 0.5, minSamples = 1, diff --git a/R/methods-Params.R b/R/methods-Params.R index aa1b1e454..22f7416fd 100644 --- a/R/methods-Params.R +++ b/R/methods-Params.R @@ -915,6 +915,38 @@ setReplaceMethod("polarity", "CentWavePredIsoParam", function(object, value) { return(object) }) +## IMCentWaveParam + +#' @description \code{ppmMerging},\code{ppmMerging<-}: getter and +#' setter for the \code{ppmMerging} slot of the object. +#' +#' @rdname findChromPeaks-centWaveIonMobility +setMethod("ppmMerging", "IMCentWaveParam", function(object){ + return(object@ppmMerging)}) +#' @aliases ppmMerging<- +#' +#' @rdname findChromPeaks-centWaveIonMobility +setReplaceMethod("ppmMerging", "IMCentWaveParam", function(object, value) { + object@ppmMerging <- value + if (validObject(object)) + return(object) +}) + +#' @description \code{binWidthIM},\code{binWidthIM<-}: getter and +#' setter for the \code{binWidthIM} slot of the object. +#' +#' @rdname findChromPeaks-centWaveIonMobility +setMethod("binWidthIM", "IMCentWaveParam", function(object){ + return(object@binWidthIM)}) +#' @aliases binWidthIM<- +#' +#' @rdname findChromPeaks-centWaveIonMobility +setReplaceMethod("binWidthIM", "IMCentWaveParam", function(object, value) { + object@binWidthIM <- value + if (validObject(object)) + return(object) +}) + ############################################################ ## PeakDensityParam diff --git a/data/IM_test_data.rds b/data/IM_test_data.rds new file mode 100644 index 000000000..c1542746e Binary files /dev/null and b/data/IM_test_data.rds differ diff --git a/man/do_findChromPeaks_IM_centWave.Rd b/man/do_findChromPeaks_IM_centWave.Rd new file mode 100644 index 000000000..3df9bd655 --- /dev/null +++ b/man/do_findChromPeaks_IM_centWave.Rd @@ -0,0 +1,152 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/do_findChromPeaks-functions.R +\name{do_findChromPeaks_IM_centWave} +\alias{do_findChromPeaks_IM_centWave} +\title{Core API for Centwave-based ion-mobility peak picking} +\usage{ +do_findChromPeaks_IM_centWave( + spec, + ppm = 25, + peakwidth = c(20, 50), + snthresh = 10, + prefilter = c(3, 100), + mzCenterFun = "wMean", + integrate = 1, + mzdiff = -0.001, + fitgauss = FALSE, + noise = 0, + verboseColumns = FALSE, + roiList = list(), + firstBaselineCheck = TRUE, + roiScales = numeric(), + sleep = 0, + extendLengthMSW = FALSE, + ppmMerging = 10, + binWidthIM = 0.01 +) +} +\arguments{ +\item{ppm}{\code{numeric(1)} defining the maximal tolerated m/z deviation in +consecutive scans in parts per million (ppm) for the initial ROI +definition.} + +\item{peakwidth}{\code{numeric(2)} with the expected approximate +peak width in chromatographic space. Given as a range (min, max) +in seconds.} + +\item{snthresh}{\code{numeric(1)} defining the signal to noise ratio cutoff.} + +\item{prefilter}{\code{numeric(2)}: \code{c(k, I)} specifying the prefilter +step for the first analysis step (ROI detection). Mass traces are only +retained if they contain at least \code{k} peaks with intensity +\code{>= I}.} + +\item{mzCenterFun}{Name of the function to calculate the m/z center of the +chromatographic peak. Allowed are: \code{"wMean"}: intensity weighted +mean of the peak's m/z values, \code{"mean"}: mean of the peak's m/z +values, \code{"apex"}: use the m/z value at the peak apex, +\code{"wMeanApex3"}: intensity weighted mean of the m/z value at the +peak apex and the m/z values left and right of it and \code{"meanApex3"}: +mean of the m/z value of the peak apex and the m/z values left and right +of it.} + +\item{integrate}{Integration method. For \code{integrate = 1} peak limits +are found through descent on the mexican hat filtered data, for +\code{integrate = 2} the descent is done on the real data. The latter +method is more accurate but prone to noise, while the former is more +robust, but less exact.} + +\item{mzdiff}{\code{numeric(1)} representing the minimum difference in m/z +dimension required for peaks with overlapping retention times; can be +negative to allow overlap. During peak post-processing, peaks +defined to be overlapping are reduced to the one peak with the largest +signal.} + +\item{fitgauss}{\code{logical(1)} whether or not a Gaussian should be fitted +to each peak. This affects mostly the retention time position of the +peak.} + +\item{noise}{\code{numeric(1)} allowing to set a minimum intensity required +for centroids to be considered in the first analysis step (centroids with +intensity \code{< noise} are omitted from ROI detection).} + +\item{verboseColumns}{\code{logical(1)} whether additional peak meta data +columns should be returned.} + +\item{roiList}{An optional list of regions-of-interest (ROI) representing +detected mass traces. If ROIs are submitted the first analysis step is +omitted and chromatographic peak detection is performed on the submitted +ROIs. Each ROI is expected to have the following elements specified: +\code{scmin} (start scan index), \code{scmax} (end scan index), +\code{mzmin} (minimum m/z), \code{mzmax} (maximum m/z), \code{length} +(number of scans), \code{intensity} (summed intensity). Each ROI should +be represented by a \code{list} of elements or a single row +\code{data.frame}.} + +\item{firstBaselineCheck}{\code{logical(1)}. If \code{TRUE} continuous +data within regions of interest is checked to be above the first baseline. +In detail, a first rough estimate of the noise is calculated and peak +detection is performed only in regions in which multiple sequential +signals are higher than this first estimated baseline/noise level.} + +\item{roiScales}{Optional numeric vector with length equal to \code{roiList} +defining the scale for each region of interest in \code{roiList} that +should be used for the centWave-wavelets.} + +\item{sleep}{\code{numeric(1)} defining the number of seconds to wait between +iterations. Defaults to \code{sleep = 0}. If \code{> 0} a plot is +generated visualizing the identified chromatographic peak. Note: this +argument is for backward compatibility only and will be removed in +future.} + +\item{extendLengthMSW}{Option to force centWave to use all scales when +running centWave rather than truncating with the EIC length. Uses the "open" +method to extend the EIC to a integer base-2 length prior to being passed to +\code{convolve} rather than the default "reflect" method. See +https://github.com/sneumann/xcms/issues/445 for more information.} + +\item{ppmMerging}{The maximum mass deviation allowed when grouping individual +IM scans into frames. Data points within \code{ppmMerging} ppm will be +summed up into a single value and the reported mz will be their weighted +average.} + +\item{binWidthIM}{The bin size used when calculating the mobilograms to resolve +the peaks into the ion-mobility dimension. Lower values will give better resolution +if the data allows it, but can also generate spurious peaks.} +} +\value{ +A matrix, each row representing an identified peak, with columns: + \describe{ + \item{mz}{m/z value of the peak at the apex position.} + \item{mzmin}{Minimum m/z of the peak.} + \item{mzmax}{Maximum m/z of the peak.} + \item{rt}{Retention time value of the peak at the apex position.} + \item{rtmin}{Minimum retention time of the peak.} + \item{rtmax}{Maximum retention time of the peak.} + \item{im}{Ion mobility value of the peak at the apex position.} + \item{immin}{Minimum ion mobility value of the peak.} + \item{immax}{Maximum ion mobility value of the peak.} + \item{maxo}{Maximum intensity of the peak.} + \item{into}{Integrated (original) intensity of the peak.} + \item{intb}{Always \code{NA}.} + \item{sn}{Always \code{NA}} + } +} +\description{ +Performs an extension of CentWave peak-picking on LC-IM-MS MS1 + data. First it joins all scans into frames and performs .centWave_orig on + the summarized LC-MS-like data. From each peak, it calculates its mobilogram and + performs a second peak-picking on the IM dimension, resolving the peaks. +} +\seealso{ +Other core peak detection functions: +\code{\link{do_findChromPeaks_centWaveWithPredIsoROIs}()}, +\code{\link{do_findChromPeaks_centWave}()}, +\code{\link{do_findChromPeaks_massifquant}()}, +\code{\link{do_findChromPeaks_matchedFilter}()}, +\code{\link{do_findPeaks_MSW}()} +} +\author{ +Roger Gine, Johannes Rainer +} +\concept{core peak detection functions} diff --git a/man/do_findChromPeaks_centWave.Rd b/man/do_findChromPeaks_centWave.Rd index 663b557d1..e2f8a95e9 100644 --- a/man/do_findChromPeaks_centWave.Rd +++ b/man/do_findChromPeaks_centWave.Rd @@ -214,6 +214,7 @@ Ralf Tautenhahn, Christoph B\"{o}ttcher, and Steffen Neumann "Highly \code{\link{centWave}} for the standard user interface method. Other core peak detection functions: +\code{\link{do_findChromPeaks_IM_centWave}()}, \code{\link{do_findChromPeaks_centWaveWithPredIsoROIs}()}, \code{\link{do_findChromPeaks_massifquant}()}, \code{\link{do_findChromPeaks_matchedFilter}()}, diff --git a/man/do_findChromPeaks_centWaveWithPredIsoROIs.Rd b/man/do_findChromPeaks_centWaveWithPredIsoROIs.Rd index 0591e8fad..e5a88b6f6 100644 --- a/man/do_findChromPeaks_centWaveWithPredIsoROIs.Rd +++ b/man/do_findChromPeaks_centWaveWithPredIsoROIs.Rd @@ -222,6 +222,7 @@ For more details on the centWave algorithm see } \seealso{ Other core peak detection functions: +\code{\link{do_findChromPeaks_IM_centWave}()}, \code{\link{do_findChromPeaks_centWave}()}, \code{\link{do_findChromPeaks_massifquant}()}, \code{\link{do_findChromPeaks_matchedFilter}()}, diff --git a/man/do_findChromPeaks_massifquant.Rd b/man/do_findChromPeaks_massifquant.Rd index 0f0b4b1d2..88530dc95 100644 --- a/man/do_findChromPeaks_massifquant.Rd +++ b/man/do_findChromPeaks_massifquant.Rd @@ -204,6 +204,7 @@ detection" \emph{Bioinformatics} 2014, 30(18):2636-43. \code{\link{massifquant}} for the standard user interface method. Other core peak detection functions: +\code{\link{do_findChromPeaks_IM_centWave}()}, \code{\link{do_findChromPeaks_centWaveWithPredIsoROIs}()}, \code{\link{do_findChromPeaks_centWave}()}, \code{\link{do_findChromPeaks_matchedFilter}()}, diff --git a/man/do_findChromPeaks_matchedFilter.Rd b/man/do_findChromPeaks_matchedFilter.Rd index 9932925b6..b362b6f2d 100644 --- a/man/do_findChromPeaks_matchedFilter.Rd +++ b/man/do_findChromPeaks_matchedFilter.Rd @@ -166,6 +166,7 @@ Profiling Using Nonlinear Peak Alignment, Matching, and Identification" \code{\link{matchedFilter}} for the standard user interface method. Other core peak detection functions: +\code{\link{do_findChromPeaks_IM_centWave}()}, \code{\link{do_findChromPeaks_centWaveWithPredIsoROIs}()}, \code{\link{do_findChromPeaks_centWave}()}, \code{\link{do_findChromPeaks_massifquant}()}, diff --git a/man/do_findPeaks_MSW.Rd b/man/do_findPeaks_MSW.Rd index e918b25ba..ac34ab611 100644 --- a/man/do_findPeaks_MSW.Rd +++ b/man/do_findPeaks_MSW.Rd @@ -55,6 +55,7 @@ This is a wrapper around the peak picker in Bioconductor's \code{MassSpecWavelet} package. Other core peak detection functions: +\code{\link{do_findChromPeaks_IM_centWave}()}, \code{\link{do_findChromPeaks_centWaveWithPredIsoROIs}()}, \code{\link{do_findChromPeaks_centWave}()}, \code{\link{do_findChromPeaks_massifquant}()}, diff --git a/man/findChromPeaks-centWave.Rd b/man/findChromPeaks-centWave.Rd index 8157aa4b3..f076cbbef 100644 --- a/man/findChromPeaks-centWave.Rd +++ b/man/findChromPeaks-centWave.Rd @@ -385,6 +385,7 @@ detection in purely chromatographic data. the peak detection. Other peak detection methods: +\code{\link{findChromPeaks-centWaveIonMobility}}, \code{\link{findChromPeaks-centWaveWithPredIsoROIs}}, \code{\link{findChromPeaks-massifquant}}, \code{\link{findChromPeaks-matchedFilter}}, diff --git a/man/findChromPeaks-centWaveIonMobility.Rd b/man/findChromPeaks-centWaveIonMobility.Rd new file mode 100644 index 000000000..01b28fa2f --- /dev/null +++ b/man/findChromPeaks-centWaveIonMobility.Rd @@ -0,0 +1,186 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DataClasses.R, R/functions-Params.R, +% R/methods-Params.R +\docType{class} +\name{findChromPeaks-centWaveIonMobility} +\alias{findChromPeaks-centWaveIonMobility} +\alias{centWaveIonMobility} +\alias{IMCentWaveParam-class} +\alias{IMCentWaveParam} +\alias{ppmMerging,IMCentWaveParam-method} +\alias{ppmMerging<-,IMCentWaveParam-method} +\alias{ppmMerging<-} +\alias{binWidthIM,IMCentWaveParam-method} +\alias{binWidthIM<-,IMCentWaveParam-method} +\alias{binWidthIM<-} +\title{Centwave-based ion-mobility peak picking} +\usage{ +IMCentWaveParam( + ppm = 25, + peakwidth = c(20, 50), + snthresh = 10, + prefilter = c(3, 100), + mzCenterFun = "wMean", + integrate = 1L, + mzdiff = -0.001, + fitgauss = FALSE, + noise = 0, + verboseColumns = FALSE, + roiList = list(), + firstBaselineCheck = TRUE, + roiScales = numeric(), + extendLengthMSW = FALSE, + ppmMerging = 10, + binWidthIM = 0.02 +) + +\S4method{ppmMerging}{IMCentWaveParam}(object) + +\S4method{ppmMerging}{IMCentWaveParam}(object) <- value + +\S4method{binWidthIM}{IMCentWaveParam}(object) + +\S4method{binWidthIM}{IMCentWaveParam}(object) <- value +} +\arguments{ +\item{ppm}{\code{numeric(1)} defining the maximal tolerated m/z deviation in +consecutive scans in parts per million (ppm) for the initial ROI +definition.} + +\item{peakwidth}{\code{numeric(2)} with the expected approximate +peak width in chromatographic space. Given as a range (min, max) +in seconds.} + +\item{snthresh}{\code{numeric(1)} defining the signal to noise ratio cutoff.} + +\item{prefilter}{\code{numeric(2)}: \code{c(k, I)} specifying the prefilter +step for the first analysis step (ROI detection). Mass traces are only +retained if they contain at least \code{k} peaks with intensity +\code{>= I}.} + +\item{mzCenterFun}{Name of the function to calculate the m/z center of the +chromatographic peak. Allowed are: \code{"wMean"}: intensity weighted +mean of the peak's m/z values, \code{"mean"}: mean of the peak's m/z +values, \code{"apex"}: use the m/z value at the peak apex, +\code{"wMeanApex3"}: intensity weighted mean of the m/z value at the +peak apex and the m/z values left and right of it and \code{"meanApex3"}: +mean of the m/z value of the peak apex and the m/z values left and right +of it.} + +\item{integrate}{Integration method. For \code{integrate = 1} peak limits +are found through descent on the mexican hat filtered data, for +\code{integrate = 2} the descent is done on the real data. The latter +method is more accurate but prone to noise, while the former is more +robust, but less exact.} + +\item{mzdiff}{\code{numeric(1)} representing the minimum difference in m/z +dimension required for peaks with overlapping retention times; can be +negative to allow overlap. During peak post-processing, peaks +defined to be overlapping are reduced to the one peak with the largest +signal.} + +\item{fitgauss}{\code{logical(1)} whether or not a Gaussian should be fitted +to each peak. This affects mostly the retention time position of the +peak.} + +\item{noise}{\code{numeric(1)} allowing to set a minimum intensity required +for centroids to be considered in the first analysis step (centroids with +intensity \code{< noise} are omitted from ROI detection).} + +\item{verboseColumns}{\code{logical(1)} whether additional peak meta data +columns should be returned.} + +\item{roiList}{An optional list of regions-of-interest (ROI) representing +detected mass traces. If ROIs are submitted the first analysis step is +omitted and chromatographic peak detection is performed on the submitted +ROIs. Each ROI is expected to have the following elements specified: +\code{scmin} (start scan index), \code{scmax} (end scan index), +\code{mzmin} (minimum m/z), \code{mzmax} (maximum m/z), \code{length} +(number of scans), \code{intensity} (summed intensity). Each ROI should +be represented by a \code{list} of elements or a single row +\code{data.frame}.} + +\item{firstBaselineCheck}{\code{logical(1)}. If \code{TRUE} continuous +data within regions of interest is checked to be above the first baseline. +In detail, a first rough estimate of the noise is calculated and peak +detection is performed only in regions in which multiple sequential +signals are higher than this first estimated baseline/noise level.} + +\item{roiScales}{Optional numeric vector with length equal to \code{roiList} +defining the scale for each region of interest in \code{roiList} that +should be used for the centWave-wavelets.} + +\item{extendLengthMSW}{Option to force centWave to use all scales when +running centWave rather than truncating with the EIC length. Uses the "open" +method to extend the EIC to a integer base-2 length prior to being passed to +\code{convolve} rather than the default "reflect" method. See +https://github.com/sneumann/xcms/issues/445 for more information.} + +\item{ppmMerging}{The maximum mass deviation allowed when grouping individual +IM scans into frames. Data points within \code{ppmMerging} ppm will be +summed up into a single value and the reported mz will be their weighted +average.} + +\item{binWidthIM}{The bin size used when calculating the mobilograms to resolve +the peaks into the ion-mobility dimension. Lower values will give better resolution +if the data allows it, but can also generate spurious peaks.} + +\item{object}{For \code{findChromPeaks}: an + \code{\link{OnDiskMSnExp}} object containing the MS- and all + other experiment-relevant data. + + For all other methods: a parameter object.} + +\item{value}{The value for the slot.} +} +\value{ +The \code{IMCentWaveParam} function returns a + \code{IMCentWaveParam} class instance with all of the settings + specified for the centWave-based peak detection in chromatographic + + ion mobility data. +} +\description{ +Performs an extension of CentWave peak-picking on LC-IM-MS MS1 + data: first it joins all mobility scans into frames and performs .centWave_orig on + the summarized LC-MS-like data; then, from each peak, it calculates its mobilogram and + performs a second peak-picking on the IM dimension, resolving the peaks. + +The \code{IMCentWaveParam} class allows to specify all + settings for + Instances should be created with the \code{IMCentWaveParam} + constructor. See also the documentation of the + \code{\link{CentWaveParam}} for all methods and arguments this class + inherits. + +\code{ppmMerging},\code{ppmMerging<-}: getter and + setter for the \code{ppmMerging} slot of the object. + +\code{binWidthIM},\code{binWidthIM<-}: getter and + setter for the \code{binWidthIM} slot of the object. +} +\details{ +See \code{\link{centWave}} for details on the centWave method. +} +\section{Slots}{ + +\describe{ +\item{\code{ppm,peakwidth,snthresh,prefilter,mzCenterFun,integrate,mzdiff,fitgauss,noise,verboseColumns,roiList,firstBaselineCheck,roiScales,ppmMerging,binWidthIM}}{See corresponding parameter above.} +}} + +\seealso{ +The \code{\link{do_findChromPeaks_IM_centWave}} core + API function and \code{\link{CentWaveParam}} for the class the + \code{IMCentWaveParam} extends. + +Other peak detection methods: +\code{\link{findChromPeaks-centWaveWithPredIsoROIs}}, +\code{\link{findChromPeaks-centWave}}, +\code{\link{findChromPeaks-massifquant}}, +\code{\link{findChromPeaks-matchedFilter}}, +\code{\link{findChromPeaks}()}, +\code{\link{findPeaks-MSW}} +} +\author{ +Roger Gine, Johannes Rainer +} +\concept{peak detection methods} diff --git a/man/findChromPeaks-centWaveWithPredIsoROIs.Rd b/man/findChromPeaks-centWaveWithPredIsoROIs.Rd index 73cef5e4c..178c16ac2 100644 --- a/man/findChromPeaks-centWaveWithPredIsoROIs.Rd +++ b/man/findChromPeaks-centWaveWithPredIsoROIs.Rd @@ -286,6 +286,7 @@ The \code{\link{do_findChromPeaks_centWaveWithPredIsoROIs}} core the peak detection. Other peak detection methods: +\code{\link{findChromPeaks-centWaveIonMobility}}, \code{\link{findChromPeaks-centWave}}, \code{\link{findChromPeaks-massifquant}}, \code{\link{findChromPeaks-matchedFilter}}, diff --git a/man/findChromPeaks-massifquant.Rd b/man/findChromPeaks-massifquant.Rd index 38a89e8c3..e304b4d22 100644 --- a/man/findChromPeaks-massifquant.Rd +++ b/man/findChromPeaks-massifquant.Rd @@ -411,6 +411,7 @@ The \code{\link{do_findChromPeaks_massifquant}} core API function the peak detection. Other peak detection methods: +\code{\link{findChromPeaks-centWaveIonMobility}}, \code{\link{findChromPeaks-centWaveWithPredIsoROIs}}, \code{\link{findChromPeaks-centWave}}, \code{\link{findChromPeaks-matchedFilter}}, diff --git a/man/findChromPeaks-matchedFilter.Rd b/man/findChromPeaks-matchedFilter.Rd index b622757a5..708e884c8 100644 --- a/man/findChromPeaks-matchedFilter.Rd +++ b/man/findChromPeaks-matchedFilter.Rd @@ -329,6 +329,7 @@ peak detection in purely chromatographic data. the chromatographic peak detection. Other peak detection methods: +\code{\link{findChromPeaks-centWaveIonMobility}}, \code{\link{findChromPeaks-centWaveWithPredIsoROIs}}, \code{\link{findChromPeaks-centWave}}, \code{\link{findChromPeaks-massifquant}}, diff --git a/man/findChromPeaks.Rd b/man/findChromPeaks.Rd index d5efb715c..2dd06480e 100644 --- a/man/findChromPeaks.Rd +++ b/man/findChromPeaks.Rd @@ -91,6 +91,7 @@ chromatographic peaks. \code{\link[=manualChromPeaks]{manualChromPeaks()}} to manually add/define chromatographic peaks. Other peak detection methods: +\code{\link{findChromPeaks-centWaveIonMobility}}, \code{\link{findChromPeaks-centWaveWithPredIsoROIs}}, \code{\link{findChromPeaks-centWave}}, \code{\link{findChromPeaks-massifquant}}, diff --git a/man/findPeaks-MSW.Rd b/man/findPeaks-MSW.Rd index 337afc042..111d7b096 100644 --- a/man/findPeaks-MSW.Rd +++ b/man/findPeaks-MSW.Rd @@ -300,6 +300,7 @@ The \code{\link{do_findPeaks_MSW}} core API function the peak detection. Other peak detection methods: +\code{\link{findChromPeaks-centWaveIonMobility}}, \code{\link{findChromPeaks-centWaveWithPredIsoROIs}}, \code{\link{findChromPeaks-centWave}}, \code{\link{findChromPeaks-massifquant}}, diff --git a/tests/testthat.R b/tests/testthat.R index 948ef9b74..8508877e9 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -64,6 +64,20 @@ pest_dda <- findChromPeaks(pest_dda, param = cwp) ## sciex_data <- readMSData(fl, mode = "onDisk") ## sciex_data <- pickPeaks(sciex_data) +## IM data +if(system.file("data/IM_test_data.rds", package = "xcms") != ""){ + library(MsExperiment) + im_spec <- readRDS(system.file("data/IM_test_data.rds", package = "xcms")) + im_exp <- MsExperiment() + spectra(im_exp) <- im_spec + sampleData(im_exp) <- DataFrame( + raw_file = "testfile" + ) + im_exp <- linkSampleData(im_exp, + with = "sampleData.raw_file = spectra.dataOrigin") + +} + test_check("xcms") bpstop(prm) diff --git a/tests/testthat/test_Param_classes.R b/tests/testthat/test_Param_classes.R index a20ff3554..1a133ee00 100644 --- a/tests/testthat/test_Param_classes.R +++ b/tests/testthat/test_Param_classes.R @@ -482,6 +482,121 @@ test_that("CentWavePredIsoParam works", { expect_equal(L$snthresh, 123) }) +test_that("IMCentWaveParam works", { + skip_on_os(os = "windows", arch = "i386") + + ## Check getter/setter methods: + p <- new("IMCentWaveParam", ppm = 14) + expect_equal(ppm(p), 14) + ppm(p) <- 13 + expect_equal(ppm(p), 13) + p <- IMCentWaveParam(ppm = 21) + expect_equal(ppm(p), 21) + expect_error(IMCentWaveParam(ppm = -4)) + + p <- new("IMCentWaveParam", peakwidth = c(1, 2)) + expect_equal(peakwidth(p), c(1, 2)) + peakwidth(p) <- c(2, 3) + expect_equal(peakwidth(p), c(2, 3)) + p <- IMCentWaveParam(peakwidth = c(3, 4)) + expect_equal(peakwidth(p), c(3, 4)) + expect_error(IMCentWaveParam(peakwidth = 1:3)) + + p <- new("IMCentWaveParam", snthresh = 5) + expect_equal(snthresh(p), 5) + snthresh(p) <- 6 + expect_equal(snthresh(p), 6) + p <- IMCentWaveParam(snthresh = 7) + expect_equal(snthresh(p), 7) + expect_error(IMCentWaveParam(snthresh = 1:3)) + + p <- new("IMCentWaveParam", prefilter = c(1, 2)) + expect_equal(prefilter(p), c(1, 2)) + prefilter(p) <- c(2, 3) + expect_equal(prefilter(p), c(2, 3)) + p <- IMCentWaveParam(prefilter = c(3, 4)) + expect_equal(prefilter(p), c(3, 4)) + expect_error(IMCentWaveParam(prefilter = 1:3)) + + p <- new("IMCentWaveParam", mzCenterFun = "meanApex3") + expect_equal(mzCenterFun(p), "meanApex3") + mzCenterFun(p) <- "mean" + expect_equal(mzCenterFun(p), "mean") + p <- IMCentWaveParam(mzCenterFun = "mean") + expect_equal(mzCenterFun(p), "mean") + expect_error(IMCentWaveParam(mzCenterFun = "median")) + + p <- new("IMCentWaveParam", integrate = 2L) + expect_equal(integrate(p), 2L) + integrate(p) <- 1L + expect_equal(integrate(p), 1L) + p <- IMCentWaveParam(integrate = 2L) + expect_equal(integrate(p), 2L) + expect_error(IMCentWaveParam(integrate = 3L)) + + p <- new("IMCentWaveParam", mzdiff = 1) + expect_equal(mzdiff(p), 1) + mzdiff(p) <- 2 + expect_equal(mzdiff(p), 2) + p <- IMCentWaveParam(mzdiff = 3) + expect_equal(mzdiff(p), 3) + expect_error(IMCentWaveParam(mzdiff = 2:3)) + + p <- new("IMCentWaveParam", fitgauss = TRUE) + expect_equal(fitgauss(p), TRUE) + fitgauss(p) <- FALSE + expect_equal(fitgauss(p), FALSE) + p <- IMCentWaveParam(fitgauss = TRUE) + expect_equal(fitgauss(p), TRUE) + expect_error(IMCentWaveParam(fitgauss = c(TRUE, FALSE))) + + p <- new("IMCentWaveParam", noise = 3) + expect_equal(noise(p), 3) + noise(p) <- 6 + expect_equal(noise(p), 6) + p <- IMCentWaveParam(noise = 8) + expect_equal(noise(p), 8) + expect_error(IMCentWaveParam(noise = c(3, 5))) + + p <- new("IMCentWaveParam", verboseColumns = TRUE) + expect_equal(verboseColumns(p), TRUE) + verboseColumns(p) <- FALSE + expect_equal(verboseColumns(p), FALSE) + p <- IMCentWaveParam(verboseColumns = TRUE) + expect_equal(verboseColumns(p), TRUE) + expect_error(IMCentWaveParam(verboseColumns = c(TRUE, FALSE))) + + p <- new("IMCentWaveParam", firstBaselineCheck = TRUE) + expect_equal(firstBaselineCheck(p), TRUE) + firstBaselineCheck(p) <- FALSE + expect_equal(firstBaselineCheck(p), FALSE) + p <- IMCentWaveParam(firstBaselineCheck = FALSE) + expect_equal(firstBaselineCheck(p), FALSE) + expect_error(IMCentWaveParam(firstBaselineCheck = c(TRUE, FALSE))) + + p <- new("IMCentWaveParam", ppmMerging = 10) + expect_equal(ppmMerging(p), 10) + ppmMerging(p) <- 20 + expect_equal(ppmMerging(p), 20) + p <- IMCentWaveParam(ppmMerging = 30) + expect_equal(ppmMerging(p), 30) + expect_error(IMCentWaveParam(ppmMerging = c(10, 60))) + + p <- new("IMCentWaveParam", binWidthIM = 0.03) + expect_equal(binWidthIM(p), 0.03) + binWidthIM(p) <- 0.05 + expect_equal(binWidthIM(p), 0.05) + p <- IMCentWaveParam(binWidthIM = 0.01) + expect_equal(binWidthIM(p), 0.01) + expect_error(IMCentWaveParam(binWidthIM = c(0.01, 0.08))) + + ## Check the .param2list method: + p <- new("IMCentWaveParam", snthresh = 123) + L <- .param2list(p) + expect_equal(L$snthresh, 123) +}) + + test_that("PeakDensityParam works", { skip_on_os(os = "windows", arch = "i386") diff --git a/tests/testthat/test_do_findChromPeaks-functions.R b/tests/testthat/test_do_findChromPeaks-functions.R index 94aebf335..e708ab2a2 100644 --- a/tests/testthat/test_do_findChromPeaks-functions.R +++ b/tests/testthat/test_do_findChromPeaks-functions.R @@ -88,6 +88,49 @@ test_that("do_findChromPeaks_massifquant works", { expect_true(nrow(res_3) < nrow(res_2)) }) +test_that("do_findChromPeaks_IM_centWave works", { + skip_on_os(os = "windows", arch = "i386") + skip_if(system.file("data/IM_test_data.rds", package = "xcms") == "") + res_1 <- do_findChromPeaks_IM_centWave(im_spec, + peakwidth = c(1,5), + snthresh = 0, + ppmMerging = 50) + res_2 <- do_findChromPeaks_IM_centWave(im_spec, + peakwidth = c(1,5), + snthresh = 0, + ppmMerging = 10) + expect_true(nrow(res_2) > nrow(res_1)) # Using a higher ppmMerging yields less peaks +}) + +test_that("extract_mobilogram works", { + skip_on_os(os = "windows", arch = "i386") + skip_if(system.file("data/IM_test_data.rds", package = "xcms") == "") + mobilogram <- .extract_mobilogram(peaksData(im_spec), + peak = data.frame(mzmin = 286.1982, mzmax = 286.2051, + rtmin = 357.0347, rtmax = 359.838), + rt = rtime(im_spec), + im = im_spec$inv_ion_mobility) + expect_length(mobilogram, 2) + expect_equal(range(mobilogram$x), c(0, 12360727)) + expect_equal(range(mobilogram$mids), c(0.005, 0.995)) +}) + + +test_that("split_mobilogram works", { + skip_on_os(os = "windows", arch = "i386") + skip_if(system.file("data/IM_test_data.rds", package = "xcms") == "") + mobilogram <- .extract_mobilogram(peaksData(im_spec), + peak = data.frame(mzmin = 286.1982, mzmax = 286.2051, + rtmin = 357.0347, rtmax = 359.838), + rt = rtime(im_spec), + im = im_spec$inv_ion_mobility) + split <- .split_mobilogram(mobilogram) + expect_length(split, 1) + expect_length(split[[1]], 3) + expect_equal(split[[1]], c(0.795, 0.825, 0.865)) +}) + + test_that("do_findChromPeaks_matchedFilter works", { skip_on_os(os = "windows", arch = "i386")