diff --git a/README.md b/README.md index 733012d..65f7e1e 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,6 @@ find an overview of actions available in the plugin. | annotate-mags-card | Annotate MAGs with antimicrobial resistance gene information from CARD. | [rgi](https://github.com/arpcard/rgi) | main, load | | annotate-reads-card | Annotate metagenomic reads with antimicrobial resistance gene information from CARD. | [rgi](https://github.com/arpcard/rgi) | bwt, load | | heatmap | Create a heatmap from annotate-mags-card output files. | [rgi](https://github.com/arpcard/rgi) | heatmap | -| visualize-annotation-stats | Plot annotate-reads-card annotation statistics. | | | - ## Dev environment This repository follows the _black_ code style. To make the development slightly easier diff --git a/ci/recipe/meta.yaml b/ci/recipe/meta.yaml index 0fd7f77..00abfca 100644 --- a/ci/recipe/meta.yaml +++ b/ci/recipe/meta.yaml @@ -24,7 +24,6 @@ requirements: - q2templates {{ qiime2_epoch }}.* - q2cli {{ qiime2_epoch }}.* - rgi - - altair test: requires: diff --git a/q2_amr/assets/rgi/annotation_stats/index.html b/q2_amr/assets/rgi/annotation_stats/index.html deleted file mode 100644 index f32cc0c..0000000 --- a/q2_amr/assets/rgi/annotation_stats/index.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} - -
- -
-
-

CARD annotation: mapping statistics

-
-
- -
- -
-
- -
-
- -
- -
-
-

Displayed are the mapping statistics of the amr annotation.
- Shown on top are the mapped reads per sample and below
- the mapped reads per sample as a percentage of total reads.

-
-
-{% endblock %} - -{% block footer %} -{% set loading_selector = '#loading' %} -{% include 'js-error-handler.html' %} - -{% endblock %} diff --git a/q2_amr/card/reads.py b/q2_amr/card/reads.py index cd9c8d9..812aa86 100644 --- a/q2_amr/card/reads.py +++ b/q2_amr/card/reads.py @@ -2,13 +2,9 @@ import shutil import subprocess import tempfile -from distutils.dir_util import copy_tree from typing import Union -import altair as alt import pandas as pd -import pkg_resources -import q2templates from q2_types.per_sample_sequences import ( SingleLanePerSamplePairedEndFastqDirFmt, SingleLanePerSampleSingleEndFastqDirFmt, @@ -144,93 +140,3 @@ def run_rgi_bwt( f"(return code {e.returncode}), please inspect " "stdout and stderr to learn more." ) - - -def plot_sample_stats(sample_stats: dict, output_dir: str): - sample_stats_df = pd.DataFrame.from_dict(sample_stats, orient="index") - sample_stats_df.reset_index(inplace=True) - - mapped_reads_plot = ( - alt.Chart(sample_stats_df) - .mark_bar() - .encode( - x=alt.X( - "index:N", - title=None, - axis=alt.Axis(labels=False, ticks=False), - bandPosition=0.1, - ), - y=alt.Y( - "mapped_reads", - title="Mapped Reads", - scale=alt.Scale( - domain=(0, sample_stats_df["mapped_reads"].max() * 1.1) - ), - ), - tooltip=[ - alt.Tooltip("index", title="Sample"), - alt.Tooltip("mapped_reads", title="Mapped Reads"), - alt.Tooltip("total_reads", title="Total Reads"), - ], - ) - .properties(width=alt.Step(80), height=200) - ) - - percentage_plot = ( - alt.Chart(sample_stats_df) - .mark_bar() - .encode( - x=alt.X( - "index:N", title=None, axis=alt.Axis(labelAngle=15), bandPosition=0.1 - ), - y=alt.Y( - "percentage", - title="Mapped Reads (%)", - scale=alt.Scale(domain=(0, sample_stats_df["percentage"].max() * 1.1)), - ), - tooltip=[ - alt.Tooltip("index", title="Sample"), - alt.Tooltip("percentage", title="Mapped Reads (%)"), - alt.Tooltip("total_reads", title="Total Reads"), - ], - ) - .properties(width=alt.Step(80), height=200) - ) - combined_chart = alt.vconcat(mapped_reads_plot, percentage_plot, spacing=0) - combined_chart.save(os.path.join(output_dir, "sample_stats_plot.html")) - - -def extract_sample_stats(samp_dir: str): - with open(os.path.join(samp_dir, "overall_mapping_stats.txt"), "r") as f: - for line in f: - if "Total reads:" in line: - total_reads = int(line.split()[2]) - elif "Mapped reads:" in line: - mapped_reads = int(line.split()[2]) - percentage = float(line.split()[3].strip("()").strip("%")) - sample_stats_dict = { - "total_reads": total_reads, - "mapped_reads": mapped_reads, - "percentage": percentage, - } - return sample_stats_dict - - -def visualize_annotation_stats( - output_dir: str, - amr_reads_annotation: Union[ - CARDGeneAnnotationDirectoryFormat, CARDAlleleAnnotationDirectoryFormat - ], -): - directory = str(amr_reads_annotation) - sample_stats = {} - for samp in os.listdir(directory): - samp_dir = os.path.join(directory, samp) - sample_stats[samp] = extract_sample_stats(samp_dir) - plot_sample_stats(sample_stats, output_dir) - TEMPLATES = pkg_resources.resource_filename("q2_amr", "assets") - copy_tree(os.path.join(TEMPLATES, "rgi", "annotation_stats"), output_dir) - context = {"tabs": [{"title": "Mapped Reads", "url": "index.html"}]} - index = os.path.join(TEMPLATES, "rgi", "annotation_stats", "index.html") - templates = [index] - q2templates.render(templates, output_dir, context=context) diff --git a/q2_amr/tests/__init__.py b/q2_amr/card/tests/__init__.py similarity index 100% rename from q2_amr/tests/__init__.py rename to q2_amr/card/tests/__init__.py diff --git a/q2_amr/tests/data/DNA_fasta.fasta b/q2_amr/card/tests/data/DNA_fasta.fasta similarity index 100% rename from q2_amr/tests/data/DNA_fasta.fasta rename to q2_amr/card/tests/data/DNA_fasta.fasta diff --git a/q2_amr/tests/data/DNA_fasta_-.fasta b/q2_amr/card/tests/data/DNA_fasta_-.fasta similarity index 100% rename from q2_amr/tests/data/DNA_fasta_-.fasta rename to q2_amr/card/tests/data/DNA_fasta_-.fasta diff --git a/q2_amr/tests/data/MANIFEST_mags b/q2_amr/card/tests/data/MANIFEST_mags similarity index 100% rename from q2_amr/tests/data/MANIFEST_mags rename to q2_amr/card/tests/data/MANIFEST_mags diff --git a/q2_amr/tests/data/MANIFEST_reads_paired b/q2_amr/card/tests/data/MANIFEST_reads_paired similarity index 100% rename from q2_amr/tests/data/MANIFEST_reads_paired rename to q2_amr/card/tests/data/MANIFEST_reads_paired diff --git a/q2_amr/tests/data/MANIFEST_reads_single b/q2_amr/card/tests/data/MANIFEST_reads_single similarity index 100% rename from q2_amr/tests/data/MANIFEST_reads_single rename to q2_amr/card/tests/data/MANIFEST_reads_single diff --git a/q2_amr/tests/data/card.tar.bz2 b/q2_amr/card/tests/data/card.tar.bz2 similarity index 100% rename from q2_amr/tests/data/card.tar.bz2 rename to q2_amr/card/tests/data/card.tar.bz2 diff --git a/q2_amr/tests/data/card_test.json b/q2_amr/card/tests/data/card_test.json similarity index 100% rename from q2_amr/tests/data/card_test.json rename to q2_amr/card/tests/data/card_test.json diff --git a/q2_amr/tests/data/kmer_json_test.json b/q2_amr/card/tests/data/kmer_json_test.json similarity index 100% rename from q2_amr/tests/data/kmer_json_test.json rename to q2_amr/card/tests/data/kmer_json_test.json diff --git a/q2_amr/tests/data/kmer_txt_test.txt b/q2_amr/card/tests/data/kmer_txt_test.txt similarity index 100% rename from q2_amr/tests/data/kmer_txt_test.txt rename to q2_amr/card/tests/data/kmer_txt_test.txt diff --git a/q2_amr/tests/data/output.allele_mapping_data.txt b/q2_amr/card/tests/data/output.allele_mapping_data.txt similarity index 100% rename from q2_amr/tests/data/output.allele_mapping_data.txt rename to q2_amr/card/tests/data/output.allele_mapping_data.txt diff --git a/q2_amr/tests/data/output.gene_mapping_data.txt b/q2_amr/card/tests/data/output.gene_mapping_data.txt similarity index 100% rename from q2_amr/tests/data/output.gene_mapping_data.txt rename to q2_amr/card/tests/data/output.gene_mapping_data.txt diff --git a/q2_amr/tests/data/output.mags.txt b/q2_amr/card/tests/data/output.mags.txt similarity index 100% rename from q2_amr/tests/data/output.mags.txt rename to q2_amr/card/tests/data/output.mags.txt diff --git a/q2_amr/tests/data/output.overall_mapping_stats.txt b/q2_amr/card/tests/data/output.overall_mapping_stats.txt similarity index 100% rename from q2_amr/tests/data/output.overall_mapping_stats.txt rename to q2_amr/card/tests/data/output.overall_mapping_stats.txt diff --git a/q2_amr/tests/data/rgi_output.json b/q2_amr/card/tests/data/rgi_output.json similarity index 100% rename from q2_amr/tests/data/rgi_output.json rename to q2_amr/card/tests/data/rgi_output.json diff --git a/q2_amr/tests/data/rgi_output.txt b/q2_amr/card/tests/data/rgi_output.txt similarity index 100% rename from q2_amr/tests/data/rgi_output.txt rename to q2_amr/card/tests/data/rgi_output.txt diff --git a/q2_amr/tests/data/wildcard_data.tar.bz2 b/q2_amr/card/tests/data/wildcard_data.tar.bz2 similarity index 100% rename from q2_amr/tests/data/wildcard_data.tar.bz2 rename to q2_amr/card/tests/data/wildcard_data.tar.bz2 diff --git a/q2_amr/tests/card/test_database.py b/q2_amr/card/tests/test_database.py similarity index 99% rename from q2_amr/tests/card/test_database.py rename to q2_amr/card/tests/test_database.py index eb9f4a7..e8b6886 100644 --- a/q2_amr/tests/card/test_database.py +++ b/q2_amr/card/tests/test_database.py @@ -12,7 +12,7 @@ class TestAnnotateMagsCard(TestPluginBase): - package = "q2_amr.tests" + package = "q2_amr.card.tests" def mock_preprocess(self, dir, operation): if operation == "card": diff --git a/q2_amr/tests/card/test_heatmap.py b/q2_amr/card/tests/test_heatmap.py similarity index 99% rename from q2_amr/tests/card/test_heatmap.py rename to q2_amr/card/tests/test_heatmap.py index 44aee61..d7664b4 100644 --- a/q2_amr/tests/card/test_heatmap.py +++ b/q2_amr/card/tests/test_heatmap.py @@ -14,7 +14,7 @@ class TestHeatmap(TestPluginBase): - package = "q2_amr.tests" + package = "q2_amr.card.tests" def test_heatmap(self): amr_annotation = CARDAnnotationDirectoryFormat() diff --git a/q2_amr/tests/card/test_mags.py b/q2_amr/card/tests/test_mags.py similarity index 99% rename from q2_amr/tests/card/test_mags.py rename to q2_amr/card/tests/test_mags.py index d242fa2..4f39905 100644 --- a/q2_amr/tests/card/test_mags.py +++ b/q2_amr/card/tests/test_mags.py @@ -11,7 +11,7 @@ class TestAnnotateMagsCard(TestPluginBase): - package = "q2_amr.tests" + package = "q2_amr.card.tests" def mock_run_rgi_main( self, diff --git a/q2_amr/tests/card/test_reads.py b/q2_amr/card/tests/test_reads.py similarity index 77% rename from q2_amr/tests/card/test_reads.py rename to q2_amr/card/tests/test_reads.py index 151b773..5e29ac7 100644 --- a/q2_amr/tests/card/test_reads.py +++ b/q2_amr/card/tests/test_reads.py @@ -1,7 +1,6 @@ import os import shutil import subprocess -import tempfile from unittest.mock import ANY, MagicMock, call, patch from q2_types.per_sample_sequences import ( @@ -10,13 +9,7 @@ ) from qiime2.plugin.testing import TestPluginBase -from q2_amr.card.reads import ( - annotate_reads_card, - extract_sample_stats, - plot_sample_stats, - run_rgi_bwt, - visualize_annotation_stats, -) +from q2_amr.card.reads import annotate_reads_card, run_rgi_bwt from q2_amr.types import ( CARDAlleleAnnotationDirectoryFormat, CARDDatabaseDirectoryFormat, @@ -25,7 +18,7 @@ class TestAnnotateReadsCARD(TestPluginBase): - package = "q2_amr.tests" + package = "q2_amr.card.tests" @classmethod def setUpClass(cls): @@ -203,43 +196,3 @@ def test_exception_raised(self): mock_run_command.side_effect = subprocess.CalledProcessError(1, "cmd") run_rgi_bwt() self.assertEqual(str(cm.exception), expected_message) - - def test_extract_sample_stats(self): - with tempfile.TemporaryDirectory() as tmp: - mapping_stats_path = self.get_data_path("output.overall_mapping_stats.txt") - new_mapping_stats_path = os.path.join(tmp, "overall_mapping_stats.txt") - shutil.copy(mapping_stats_path, new_mapping_stats_path) - sample_stats = extract_sample_stats(tmp) - - self.assertEqual(sample_stats, self.sample_stats["sample1"]) - - def test_plot_sample_stats(self): - with tempfile.TemporaryDirectory() as tmp: - plot_sample_stats(self.sample_stats, tmp) - self.assertTrue(os.path.exists(os.path.join(tmp, "sample_stats_plot.html"))) - - def mock_plot_sample_stats(self, sample_stats, output_dir): - # Create a dummy HTML file and copy it to the output_dir - with open(os.path.join(output_dir, "sample_stats_plot.html"), "w") as file: - file.write("file") - - def test_visualize_annotation_stats(self): - # Create a CARDGeneAnnotation object - amr_reads_annotation = CARDGeneAnnotationDirectoryFormat() - - # Create two sample directories in the CARDGeneAnnotation object - for num in range(1, 3): - os.makedirs(os.path.join(str(amr_reads_annotation), f"sample{num}")) - - # Patch extract_sample_stats and plot_sample_stats with side effect - # mock_plot_sample_stats - with patch("q2_amr.card.reads.extract_sample_stats"), patch( - "q2_amr.card.reads.plot_sample_stats", - side_effect=self.mock_plot_sample_stats, - ), tempfile.TemporaryDirectory() as tmp: - # Run visualize_annotation_stats function - visualize_annotation_stats(tmp, amr_reads_annotation) - - # Assert if all expected files are created - for file in ["sample_stats_plot.html", "index.html", "q2templateassets"]: - self.assertTrue(os.path.exists(os.path.join(tmp, file))) diff --git a/q2_amr/tests/card/test_utils.py b/q2_amr/card/tests/test_utils.py similarity index 99% rename from q2_amr/tests/card/test_utils.py rename to q2_amr/card/tests/test_utils.py index a68008b..854abde 100644 --- a/q2_amr/tests/card/test_utils.py +++ b/q2_amr/card/tests/test_utils.py @@ -11,7 +11,7 @@ class TestAnnotateReadsCARD(TestPluginBase): - package = "q2_amr.tests" + package = "q2_amr.card.tests" @classmethod def setUpClass(cls): diff --git a/q2_amr/plugin_setup.py b/q2_amr/plugin_setup.py index 3cf061c..2b07523 100644 --- a/q2_amr/plugin_setup.py +++ b/q2_amr/plugin_setup.py @@ -21,7 +21,7 @@ from q2_amr.card.database import fetch_card_db from q2_amr.card.heatmap import heatmap from q2_amr.card.mags import annotate_mags_card -from q2_amr.card.reads import annotate_reads_card, visualize_annotation_stats +from q2_amr.card.reads import annotate_reads_card from q2_amr.types import ( CARDAnnotationJSONFormat, CARDAnnotationTXTFormat, @@ -214,17 +214,6 @@ citations=[citations["alcock_card_2023"]], ) -plugin.visualizers.register_function( - function=visualize_annotation_stats, - inputs={"amr_reads_annotation": SampleData[CARDAlleleAnnotation]}, - parameters={}, - input_descriptions={"amr_reads_annotation": "AMR annotations on the allele level."}, - parameter_descriptions={}, - name="Visualize mapping statistics.", - description="Visualize mapping statistics of an annotate-reads-card output.", - citations=[citations["alcock_card_2023"]], -) - # Registrations plugin.register_semantic_types( CARDDatabase, diff --git a/setup.py b/setup.py index 048b094..0ea2e18 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ package_data={ "q2_amr": [ "citations.bib", - "tests/data/*", "assets/rgi/annotation_stats/*", "assets/rgi/heatmap/*", ], @@ -34,7 +33,7 @@ "data/annotate_mags_output/*/*/*", "data/annotate_reads_output/*/*", ], - "q2_amr.tests": ["data/*"], + "q2_amr.card.tests": ["data/*"], }, zip_safe=False, )