From 2f8bf020dd5f391bbb3260ad33fa73b6094cae19 Mon Sep 17 00:00:00 2001 From: Emma Rousseau Date: Sat, 26 Oct 2024 20:39:23 +0200 Subject: [PATCH] Rseq bamstat (#155) * initial commit dedup * Revert "initial commit dedup" This reverts commit 38f586bec0ac9e4312b016e29c3aa0bd53f292b2. * initial commit * add test, test data, version, help * Update CHANGELOG.md * adjust argument names, reduce test data size --------- Co-authored-by: Robrecht Cannoodt Co-authored-by: Kai Waldrant --- CHANGELOG.md | 9 +-- src/rseqc/rseqc_bamstat/config.vsh.yaml | 59 ++++++++++++++++++ src/rseqc/rseqc_bamstat/help.txt | 18 ++++++ src/rseqc/rseqc_bamstat/script.sh | 9 +++ src/rseqc/rseqc_bamstat/test.sh | 49 +++++++++++++++ .../rseqc_bamstat/test_data/ref_output.txt | 22 +++++++ .../test_data/ref_output_mapq.txt | 22 +++++++ src/rseqc/rseqc_bamstat/test_data/sample.bam | Bin 0 -> 9240 bytes 8 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 src/rseqc/rseqc_bamstat/config.vsh.yaml create mode 100644 src/rseqc/rseqc_bamstat/help.txt create mode 100644 src/rseqc/rseqc_bamstat/script.sh create mode 100644 src/rseqc/rseqc_bamstat/test.sh create mode 100644 src/rseqc/rseqc_bamstat/test_data/ref_output.txt create mode 100644 src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt create mode 100644 src/rseqc/rseqc_bamstat/test_data/sample.bam diff --git a/CHANGELOG.md b/CHANGELOG.md index dcc783c9..5f720035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,16 +16,17 @@ * `rsem/rsem_calculate_expression`: Calculate expression levels (PR #93). -* `nanoplot`: Plotting tool for long read sequencing data and alignments (PR #95). +* `rseqc`: + - `rseqc/bam_stat`: Generate statistics from a bam file (PR #155). +* `nanoplot`: Plotting tool for long read sequencing data and alignments (PR #95). -## BREAKING CHANGES +## BUG FIXES * `falco`: Fix a typo in the `--reverse_complement` argument (PR #157). -## BUG FIXES +* `cutadapt`: Fix the the non-functional `action` parameter (PR #161). -* `cutadapt`: fix the the non-functional `action` parameter (PR #161). ## MINOR CHANGES diff --git a/src/rseqc/rseqc_bamstat/config.vsh.yaml b/src/rseqc/rseqc_bamstat/config.vsh.yaml new file mode 100644 index 00000000..6d607e2f --- /dev/null +++ b/src/rseqc/rseqc_bamstat/config.vsh.yaml @@ -0,0 +1,59 @@ +name: rseqc_bamstat +namespace: rseqc +keywords: [ rnaseq, genomics ] +description: Generate statistics from a bam file. +links: + homepage: https://rseqc.sourceforge.net/ + documentation: https://rseqc.sourceforge.net/#bam-stat-py + issue_tracker: https://github.com/MonashBioinformaticsPlatform/RSeQC/issues + repository: https://github.com/MonashBioinformaticsPlatform/RSeQC +references: + doi: 10.1093/bioinformatics/bts356 +license: GPL-3.0 +authors: + - __merge__: /src/_authors/emma_rousseau.yaml + roles: [ author, maintainer ] + +argument_groups: +- name: "Input" + arguments: + - name: "--input_file" + alternatives: -i + type: file + required: true + description: Input alignment file in BAM or SAM format. + - name: "--mapq" + alternatives: -q + type: integer + example: 30 + description: | + Minimum mapping quality (phred scaled) to determine uniquely mapped reads. Default: '30'. + +- name: "Output" + arguments: + - name: "--output" + type: file + direction: output + description: Output file (txt) with mapping quality statistics. + +resources: + - type: bash_script + path: script.sh +test_resources: + - type: bash_script + path: test.sh + - type: file + path: test_data + +engines: +- type: docker + image: python:3.10 + setup: + - type: python + packages: [ RSeQC ] + - type: docker + run: | + echo "RSeQC bam_stat.py: $(bam_stat.py --version | cut -d' ' -f2-)" > /var/software_versions.txt +runners: +- type: executable +- type: nextflow diff --git a/src/rseqc/rseqc_bamstat/help.txt b/src/rseqc/rseqc_bamstat/help.txt new file mode 100644 index 00000000..b4e9c1d9 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/help.txt @@ -0,0 +1,18 @@ +``` +bam_stat.py -h +``` + +Usage: bam_stat.py [options] + +Summarizing mapping statistics of a BAM or SAM file. + + + +Options: + --version show program's version number and exit + -h, --help show this help message and exit + -i INPUT_FILE, --input-file=INPUT_FILE + Alignment file in BAM or SAM format. + -q MAP_QUAL, --mapq=MAP_QUAL + Minimum mapping quality (phred scaled) to determine + "uniquely mapped" reads. default=30 \ No newline at end of file diff --git a/src/rseqc/rseqc_bamstat/script.sh b/src/rseqc/rseqc_bamstat/script.sh new file mode 100644 index 00000000..32927bb6 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/script.sh @@ -0,0 +1,9 @@ +#!/bin/bash + + +set -eo pipefail + +bam_stat.py \ + --input-file "${par_input_file}" \ + ${par_mapq:+--mapq "${par_mapq}"} \ +> $par_output diff --git a/src/rseqc/rseqc_bamstat/test.sh b/src/rseqc/rseqc_bamstat/test.sh new file mode 100644 index 00000000..f9180da8 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/test.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# define input and output for script + +input_bam="sample.bam" +output_summary="mapping_quality.txt" + +# run executable and tests +echo "> Running $meta_functionality_name." + +"$meta_executable" \ + --input_file "$meta_resources_dir/test_data/$input_bam" \ + --output "$output_summary" + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Checking whether output is present" +[ ! -f "$output_summary" ] && echo "$output_summary file missing" && exit 1 +[ ! -s "$output_summary" ] && echo "$output_summary file is empty" && exit 1 + +echo ">> Checking whether output is correct" +diff "$meta_resources_dir/test_data/ref_output.txt" "$meta_resources_dir/$output_summary" || { echo "Output is not correct"; exit 1; } + +############################################################################# + +echo ">>> Test 2: Test with non-default mapping quality threshold" + +output_summary="mapping_quality_mapq_50.txt" + +# run executable and tests +echo "> Running $meta_functionality_name." + +"$meta_executable" \ + --input_file "$meta_resources_dir/test_data/$input_bam" \ + --output "$output_summary" \ + --mapq 50 + +exit_code=$? +[[ $exit_code != 0 ]] && echo "Non zero exit code: $exit_code" && exit 1 + +echo ">> Checking whether output is present" +[ ! -f "$output_summary" ] && echo "$output_summary file missing" && exit 1 +[ ! -s "$output_summary" ] && echo "$output_summary file is empty" && exit 1 + +echo ">> Checking whether output is correct" +diff "$meta_resources_dir/test_data/ref_output_mapq.txt" "$meta_resources_dir/$output_summary" || { echo "Output is not correct"; exit 1; } + +exit 0 \ No newline at end of file diff --git a/src/rseqc/rseqc_bamstat/test_data/ref_output.txt b/src/rseqc/rseqc_bamstat/test_data/ref_output.txt new file mode 100644 index 00000000..6b939096 --- /dev/null +++ b/src/rseqc/rseqc_bamstat/test_data/ref_output.txt @@ -0,0 +1,22 @@ + +#================================================== +#All numbers are READ count +#================================================== + +Total records: 90 + +QC failed: 0 +Optical/PCR duplicate: 0 +Non primary hits 0 +Unmapped reads: 1 +mapq < mapq_cut (non-unique): 0 + +mapq >= mapq_cut (unique): 89 +Read-1: 45 +Read-2: 44 +Reads map to '+': 44 +Reads map to '-': 45 +Non-splice reads: 89 +Splice reads: 0 +Reads mapped in proper pairs: 88 +Proper-paired reads map to different chrom:0 diff --git a/src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt b/src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt new file mode 100644 index 00000000..be8af62f --- /dev/null +++ b/src/rseqc/rseqc_bamstat/test_data/ref_output_mapq.txt @@ -0,0 +1,22 @@ + +#================================================== +#All numbers are READ count +#================================================== + +Total records: 90 + +QC failed: 0 +Optical/PCR duplicate: 0 +Non primary hits 0 +Unmapped reads: 1 +mapq < mapq_cut (non-unique): 6 + +mapq >= mapq_cut (unique): 83 +Read-1: 42 +Read-2: 41 +Reads map to '+': 44 +Reads map to '-': 39 +Non-splice reads: 83 +Splice reads: 0 +Reads mapped in proper pairs: 83 +Proper-paired reads map to different chrom:0 diff --git a/src/rseqc/rseqc_bamstat/test_data/sample.bam b/src/rseqc/rseqc_bamstat/test_data/sample.bam new file mode 100644 index 0000000000000000000000000000000000000000..ed1e24333ba1df0efa75401d7928b790038b762a GIT binary patch literal 9240 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[Ji7oy)t%b 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 literal 0 HcmV?d00001