Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Adds find_peaks_xcms action #11

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions conda-recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ requirements:
- versioningit

run:
- bioconductor-xcms
- pymzml
- qiime2 {{ qiime2_epoch }}.*
- q2-types {{ qiime2_epoch }}.*
- q2templates {{ qiime2_epoch }}.*
- r-base

test:
requires:
Expand Down
55 changes: 55 additions & 0 deletions q2_ms/assets/find_peaks_xcms.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env Rscript

library(xcms)
library(MsExperiment)
library(MsIO)


update_params <- function(params, opt) {
for (key in names(params)) {
if (!is.null(opt[[key]])) {
params[[key]] <- opt[[key]]
}
}
return(params)
}

# Define command-line options
option_list <- list(
make_option(opt_str = "--mzml_files", type = "character"),
make_option(opt_str = "--ppm", type = "numeric"),
make_option(opt_str = "--min_peakwidth", type = "numeric"),
make_option(opt_str = "--max_peakwidth", type = "numeric"),
make_option(opt_str = "--snthresh", type = "numeric"),
make_option(opt_str = "--prefilter_k", type = "numeric"),
make_option(opt_str = "--prefilter_i", type = "numeric"),
make_option(opt_str = "--mz_center_fun", type = "numeric"),
make_option(opt_str = "--integrate", type = "integer"),
make_option(opt_str = "--mzdiff", type = "numeric"),
make_option(opt_str = "--fitgauss", type = "logical"),
make_option(opt_str = "--noise", type = "numeric"),
make_option(opt_str = "--first_baseline_check", type = "logical"),
make_option(opt_str = "--ms_level", type = "integer"),
make_option(opt_str = "--threads", type = "integer"),
make_option(opt_str = "--output_path", type = "character")
)

# Parse arguments
opt_parser <- OptionParser(option_list = option_list)
opt <- parse_args(opt_parser)

# Get full paths to mzML files and read them into an MsExperiment object
mzml_files <- list.files(opt$mzml_files, pattern = "\\.mzML$", full.names = TRUE)
msexperiment <- readMsExperiment(spectraFiles = mzml_files, sampleData = pd, BPPARAM = SerialParam())

# Load default parameters for CentWave
CentWaveParams <- CentWaveParam(method="centWave")

# Update params with command-line arguments
CentWaveParams <- update_params(CentWaveParams, opt)

# Find peaks using the CentWave algorithm
XCMSExperiment <- findChromPeaks(chr_raw, param = CentWaveParams)

# Export the XCMSExperiment object to the directory format
saveMsObject(XCMSExperiment, param = PlainTextParam(path = opt$output_path))
29 changes: 29 additions & 0 deletions q2_ms/plugin_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@

from q2_ms import __version__
from q2_ms.types import mzML, mzMLDirFmt, mzMLFormat
from q2_ms.types._format import (
MSBackendDataFormat,
MSExperimentLinkMColsFormat,
MSExperimentSampleDataFormat,
MSExperimentSampleDataLinksSpectra,
SpectraSlotsFormat,
XCMSExperimentChromPeakDataFormat,
XCMSExperimentChromPeaksFormat,
XCMSExperimentDirFmt,
XCMSExperimentFeatureDefinitionsFormat,
XCMSExperimentFeaturePeakIndexFormat,
XCMSExperimentJSONFormat,
)
from q2_ms.types._type import XCMSExperiment

citations = Citations.load("citations.bib", package="q2_ms")

Expand All @@ -25,11 +39,26 @@
# Registrations
plugin.register_semantic_types(
mzML,
XCMSExperiment,
)

plugin.register_semantic_type_to_format(SampleData[mzML], artifact_format=mzMLDirFmt)
plugin.register_semantic_type_to_format(
XCMSExperiment, artifact_format=XCMSExperimentDirFmt
)

plugin.register_formats(
mzMLFormat,
mzMLDirFmt,
MSBackendDataFormat,
MSExperimentLinkMColsFormat,
MSExperimentSampleDataFormat,
MSExperimentSampleDataLinksSpectra,
SpectraSlotsFormat,
XCMSExperimentChromPeakDataFormat,
XCMSExperimentChromPeaksFormat,
XCMSExperimentDirFmt,
XCMSExperimentFeatureDefinitionsFormat,
XCMSExperimentFeaturePeakIndexFormat,
XCMSExperimentJSONFormat,
)
7 changes: 7 additions & 0 deletions q2_ms/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ----------------------------------------------------------------------------
# Copyright (c) 2024, QIIME 2 development team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
# ----------------------------------------------------------------------------
47 changes: 47 additions & 0 deletions q2_ms/tests/tests_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from unittest.mock import call, patch

from qiime2.plugin.testing import TestPluginBase

from q2_ms.utils import EXTERNAL_CMD_WARNING, run_command


class TestRunCommand(TestPluginBase):
package = "q2_ms.tests"

@patch("subprocess.run")
@patch("builtins.print")
def test_run_command_verbose(self, mock_print, mock_subprocess_run):
# Mock command and working directory
cmd = ["echo", "Hello"]
cwd = "/test/directory"

# Run the function with verbose=True
run_command(cmd, cwd=cwd, verbose=True)

# Check if subprocess.run was called with the correct arguments
mock_subprocess_run.assert_called_once_with(cmd, check=True, cwd=cwd)

# Check if the correct print statements were called
mock_print.assert_has_calls(
[
call(EXTERNAL_CMD_WARNING),
call("\nCommand:", end=" "),
call("echo Hello", end="\n\n"),
]
)

@patch("subprocess.run")
@patch("builtins.print")
def test_run_command_non_verbose(self, mock_print, mock_subprocess_run):
# Mock command and working directory
cmd = ["echo", "Hello"]
cwd = "/test/directory"

# Run the function with verbose=False
run_command(cmd, cwd=cwd, verbose=False)

# Check if subprocess.run was called with the correct arguments
mock_subprocess_run.assert_called_once_with(cmd, check=True, cwd=cwd)

# Ensure no print statements were made
mock_print.assert_not_called()
36 changes: 33 additions & 3 deletions q2_ms/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,37 @@
#
# The full license is in the file LICENSE, distributed with this software.
# ----------------------------------------------------------------------------
from q2_ms.types._format import mzMLDirFmt, mzMLFormat
from q2_ms.types._type import mzML
from q2_ms.types._format import (
MSBackendDataFormat,
MSExperimentLinkMColsFormat,
MSExperimentSampleDataFormat,
MSExperimentSampleDataLinksSpectra,
SpectraSlotsFormat,
XCMSExperimentChromPeakDataFormat,
XCMSExperimentChromPeaksFormat,
XCMSExperimentDirFmt,
XCMSExperimentFeatureDefinitionsFormat,
XCMSExperimentFeaturePeakIndexFormat,
XCMSExperimentJSONFormat,
mzMLDirFmt,
mzMLFormat,
)
from q2_ms.types._type import XCMSExperiment, mzML

__all__ = ["mzMLFormat", "mzMLDirFmt", "mzML"]
__all__ = [
"mzMLFormat",
"mzMLDirFmt",
"mzML",
"MSBackendDataFormat",
"MSExperimentLinkMColsFormat",
"MSExperimentSampleDataFormat",
"MSExperimentSampleDataLinksSpectra",
"SpectraSlotsFormat",
"XCMSExperimentChromPeakDataFormat",
"XCMSExperimentChromPeaksFormat",
"XCMSExperimentDirFmt",
"XCMSExperimentFeatureDefinitionsFormat",
"XCMSExperimentFeaturePeakIndexFormat",
"XCMSExperimentJSONFormat",
"XCMSExperiment",
]
Loading
Loading