countmut 0.0.2__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {countmut-0.0.2 → countmut-0.0.4}/PKG-INFO +59 -42
- countmut-0.0.4/README.md +117 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut/cli.py +12 -11
- {countmut-0.0.2 → countmut-0.0.4}/countmut/core.py +59 -35
- {countmut-0.0.2 → countmut-0.0.4}/countmut.egg-info/PKG-INFO +59 -42
- {countmut-0.0.2 → countmut-0.0.4}/pyproject.toml +1 -1
- countmut-0.0.2/README.md +0 -100
- {countmut-0.0.2 → countmut-0.0.4}/LICENSE +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut/__init__.py +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut/utils.py +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut.egg-info/SOURCES.txt +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut.egg-info/dependency_links.txt +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut.egg-info/entry_points.txt +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut.egg-info/requires.txt +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/countmut.egg-info/top_level.txt +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/setup.cfg +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/tests/test_cli.py +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/tests/test_core.py +0 -0
- {countmut-0.0.2 → countmut-0.0.4}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: countmut
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Ultra-fast strand-aware mutation counter
|
|
5
5
|
Author-email: Ye Chang <yech1990@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,13 +41,13 @@ Dynamic: license-file
|
|
|
41
41
|
[](https://pepy.tech/project/countmut)
|
|
42
42
|
[](https://github.com/y9c/countmut)
|
|
43
43
|
|
|
44
|
-
**Ultra-fast strand-aware mutation counter**
|
|
44
|
+
> **Ultra-fast strand-aware mutation counter for bisulfite sequencing analysis**
|
|
45
45
|
|
|
46
|
-
CountMut
|
|
46
|
+
CountMut is a high-performance tool for counting mutations from bisulfite sequencing BAM files (BS-seq, CAM-seq, GLORI-seq, eTAM-seq). It features parallel processing, quality-based mate overlap deduplication, and optimized file I/O for maximum speed.
|
|
47
47
|
|
|
48
48
|
## Features
|
|
49
49
|
|
|
50
|
-
- 🚀 **Ultra-Fast**:
|
|
50
|
+
- 🚀 **Ultra-Fast**: Call mutation without pileup reads
|
|
51
51
|
- 🧬 **Bisulfite Support**: NS, Zf, Yf tag filtering for conversion analysis
|
|
52
52
|
- 🎯 **Accurate**: Quality-based mate overlap deduplication prevents double-counting
|
|
53
53
|
- ⚡ **Parallel**: Multi-threaded genomic window processing
|
|
@@ -72,51 +72,68 @@ countmut -i input.bam -r reference.fa -o mutations.tsv --ref-base T --mut-base C
|
|
|
72
72
|
countmut -i input.bam -r reference.fa -o mutations.tsv -t 8 --max-unc 5 --min-con 2
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
##
|
|
75
|
+
## Options
|
|
76
76
|
|
|
77
|
+
**Input/Output**
|
|
77
78
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Output:
|
|
83
|
-
-o, --output PATH Output TSV file (default: stdout)
|
|
84
|
-
|
|
85
|
-
Mutation:
|
|
86
|
-
--ref-base TEXT Reference base [default: A]
|
|
87
|
-
--mut-base TEXT Mutation base [default: G]
|
|
88
|
-
--strand [both|forward|reverse] Strand processing [default: both]
|
|
89
|
-
--region TEXT Specific region (e.g., 'chr1:1000000-2000000')
|
|
90
|
-
|
|
91
|
-
Performance:
|
|
92
|
-
-t, --threads INTEGER Number of threads [default: auto]
|
|
93
|
-
-b, --bin-size INTEGER Genomic bin size [default: 10000]
|
|
94
|
-
|
|
95
|
-
Filtering (Bisulfite):
|
|
96
|
-
--pad INTEGER Motif window padding [default: 15]
|
|
97
|
-
--trim-start INTEGER Trim 5' bases [default: 2]
|
|
98
|
-
--trim-end INTEGER Trim 3' bases [default: 2]
|
|
99
|
-
--max-unc INTEGER Max unconverted (Zf) [default: 3]
|
|
100
|
-
--min-con INTEGER Min converted (Yf) [default: 1]
|
|
101
|
-
--max-sub INTEGER Max substitutions (NS) [default: 1]
|
|
102
|
-
--min-baseq INTEGER Min base quality (Phred) [default: 20]
|
|
103
|
-
--min-mapq INTEGER Min mapping quality (MAPQ) [default: 0]
|
|
79
|
+
-i, --input PATH Input BAM file (coordinate-sorted) [required]
|
|
80
|
+
-r, --reference PATH Reference FASTA file [required]
|
|
81
|
+
-o, --output PATH Output TSV file (default: stdout)
|
|
82
|
+
-f, --force Overwrite output without prompting
|
|
104
83
|
```
|
|
105
84
|
|
|
106
|
-
**
|
|
85
|
+
**Mutation Analysis**
|
|
86
|
+
```bash
|
|
87
|
+
--ref-base TEXT Reference base to count from [default: A]
|
|
88
|
+
--mut-base TEXT Mutation base to count [default: G]
|
|
89
|
+
--strand TEXT Strand: both/forward/reverse [default: both]
|
|
90
|
+
--region TEXT Genomic region (e.g., 'chr1:1000000-2000000')
|
|
91
|
+
```
|
|
107
92
|
|
|
108
|
-
|
|
93
|
+
**Performance**
|
|
94
|
+
```bash
|
|
95
|
+
-t, --threads INTEGER Number of parallel threads [default: auto]
|
|
96
|
+
-b, --bin-size INTEGER Genomic bin size in bp [default: 10000]
|
|
97
|
+
```
|
|
109
98
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
99
|
+
**Quality Filters**
|
|
100
|
+
```bash
|
|
101
|
+
--min-baseq INTEGER Min base quality (Phred score) [default: 20]
|
|
102
|
+
--min-mapq INTEGER Min mapping quality (MAPQ) [default: 0]
|
|
103
|
+
--max-sub INTEGER Max substitutions (NS tag) [default: 1]
|
|
104
|
+
--trim-start INTEGER Trim N bases from read 5' end (fragment orientation) [default: 2]
|
|
105
|
+
--trim-end INTEGER Trim N bases from read 3' end (fragment orientation) [default: 2]
|
|
106
|
+
--max-unc INTEGER Max unconverted (Zf tag) [default: 3]
|
|
107
|
+
--min-con INTEGER Min converted (Yf tag) [default: 1]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Output Records**
|
|
111
|
+
```bash
|
|
112
|
+
-p, --pad INTEGER Motif window half-size [default: 15]
|
|
113
|
+
-s, --save-rest Include other bases (o0, o1, o2 columns)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> **Note**: BAM files must have **NS**, **Zf**, and **Yf** tags (essential for bisulfite analysis).
|
|
117
|
+
> Indices (.bai, .fai) are created automatically if missing.
|
|
118
|
+
|
|
119
|
+
## Output Format
|
|
115
120
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
TSV file with the following columns:
|
|
122
|
+
|
|
123
|
+
| Column | Description |
|
|
124
|
+
|--------|-------------|
|
|
125
|
+
| `chrom` | Chromosome name |
|
|
126
|
+
| `pos` | Genomic position (1-based) |
|
|
127
|
+
| `strand` | Strand (+ or -) |
|
|
128
|
+
| `motif` | Sequence context (2×pad+1 bp window) |
|
|
129
|
+
| `u0`, `u1`, `u2` | **Unconverted** (reference base) counts |
|
|
130
|
+
| `m0`, `m1`, `m2` | **Mutation** (mutation base only) counts |
|
|
131
|
+
| `o0`, `o1`, `o2` | **Other bases** counts (with `--save-rest`) |
|
|
132
|
+
|
|
133
|
+
**Count categories** (x0, x1, x2):
|
|
134
|
+
- **x0 (low quality)**: Bases failing quality filters (trim region, max-sub, min-mapq, min-baseq)
|
|
135
|
+
- **x1 (high conversion)**: Bases from reads with high conversion efficiency (low Zf and high Yf)
|
|
136
|
+
- **x2 (insufficient conversion)**: Bases from reads with insufficient conversion efficiency (high Zf or low Yf)
|
|
120
137
|
|
|
121
138
|
|
|
122
139
|
|
countmut-0.0.4/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# CountMut
|
|
2
|
+
|
|
3
|
+
[](https://pypi.python.org/pypi/countmut)
|
|
4
|
+
[](https://pepy.tech/project/countmut)
|
|
5
|
+
[](https://github.com/y9c/countmut)
|
|
6
|
+
|
|
7
|
+
> **Ultra-fast strand-aware mutation counter for bisulfite sequencing analysis**
|
|
8
|
+
|
|
9
|
+
CountMut is a high-performance tool for counting mutations from bisulfite sequencing BAM files (BS-seq, CAM-seq, GLORI-seq, eTAM-seq). It features parallel processing, quality-based mate overlap deduplication, and optimized file I/O for maximum speed.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- 🚀 **Ultra-Fast**: Call mutation without pileup reads
|
|
14
|
+
- 🧬 **Bisulfite Support**: NS, Zf, Yf tag filtering for conversion analysis
|
|
15
|
+
- 🎯 **Accurate**: Quality-based mate overlap deduplication prevents double-counting
|
|
16
|
+
- ⚡ **Parallel**: Multi-threaded genomic window processing
|
|
17
|
+
- 🔧 **Flexible**: Configurable filtering, strand-specific processing, auto-indexing
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install countmut
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Basic usage - auto-creates indices if needed
|
|
29
|
+
countmut -i input.bam -r reference.fa -o mutations.tsv
|
|
30
|
+
|
|
31
|
+
# Count T→C mutations (common in bisulfite sequencing)
|
|
32
|
+
countmut -i input.bam -r reference.fa -o mutations.tsv --ref-base T --mut-base C
|
|
33
|
+
|
|
34
|
+
# With custom threads and filtering
|
|
35
|
+
countmut -i input.bam -r reference.fa -o mutations.tsv -t 8 --max-unc 5 --min-con 2
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Options
|
|
39
|
+
|
|
40
|
+
**Input/Output**
|
|
41
|
+
```bash
|
|
42
|
+
-i, --input PATH Input BAM file (coordinate-sorted) [required]
|
|
43
|
+
-r, --reference PATH Reference FASTA file [required]
|
|
44
|
+
-o, --output PATH Output TSV file (default: stdout)
|
|
45
|
+
-f, --force Overwrite output without prompting
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Mutation Analysis**
|
|
49
|
+
```bash
|
|
50
|
+
--ref-base TEXT Reference base to count from [default: A]
|
|
51
|
+
--mut-base TEXT Mutation base to count [default: G]
|
|
52
|
+
--strand TEXT Strand: both/forward/reverse [default: both]
|
|
53
|
+
--region TEXT Genomic region (e.g., 'chr1:1000000-2000000')
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Performance**
|
|
57
|
+
```bash
|
|
58
|
+
-t, --threads INTEGER Number of parallel threads [default: auto]
|
|
59
|
+
-b, --bin-size INTEGER Genomic bin size in bp [default: 10000]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Quality Filters**
|
|
63
|
+
```bash
|
|
64
|
+
--min-baseq INTEGER Min base quality (Phred score) [default: 20]
|
|
65
|
+
--min-mapq INTEGER Min mapping quality (MAPQ) [default: 0]
|
|
66
|
+
--max-sub INTEGER Max substitutions (NS tag) [default: 1]
|
|
67
|
+
--trim-start INTEGER Trim N bases from read 5' end (fragment orientation) [default: 2]
|
|
68
|
+
--trim-end INTEGER Trim N bases from read 3' end (fragment orientation) [default: 2]
|
|
69
|
+
--max-unc INTEGER Max unconverted (Zf tag) [default: 3]
|
|
70
|
+
--min-con INTEGER Min converted (Yf tag) [default: 1]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Output Records**
|
|
74
|
+
```bash
|
|
75
|
+
-p, --pad INTEGER Motif window half-size [default: 15]
|
|
76
|
+
-s, --save-rest Include other bases (o0, o1, o2 columns)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> **Note**: BAM files must have **NS**, **Zf**, and **Yf** tags (essential for bisulfite analysis).
|
|
80
|
+
> Indices (.bai, .fai) are created automatically if missing.
|
|
81
|
+
|
|
82
|
+
## Output Format
|
|
83
|
+
|
|
84
|
+
TSV file with the following columns:
|
|
85
|
+
|
|
86
|
+
| Column | Description |
|
|
87
|
+
|--------|-------------|
|
|
88
|
+
| `chrom` | Chromosome name |
|
|
89
|
+
| `pos` | Genomic position (1-based) |
|
|
90
|
+
| `strand` | Strand (+ or -) |
|
|
91
|
+
| `motif` | Sequence context (2×pad+1 bp window) |
|
|
92
|
+
| `u0`, `u1`, `u2` | **Unconverted** (reference base) counts |
|
|
93
|
+
| `m0`, `m1`, `m2` | **Mutation** (mutation base only) counts |
|
|
94
|
+
| `o0`, `o1`, `o2` | **Other bases** counts (with `--save-rest`) |
|
|
95
|
+
|
|
96
|
+
**Count categories** (x0, x1, x2):
|
|
97
|
+
- **x0 (low quality)**: Bases failing quality filters (trim region, max-sub, min-mapq, min-baseq)
|
|
98
|
+
- **x1 (high conversion)**: Bases from reads with high conversion efficiency (low Zf and high Yf)
|
|
99
|
+
- **x2 (insufficient conversion)**: Bases from reads with insufficient conversion efficiency (high Zf or low Yf)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
<p align="center">
|
|
105
|
+
<img
|
|
106
|
+
src="https://raw.githubusercontent.com/y9c/y9c/master/resource/footer_line.svg?sanitize=true"
|
|
107
|
+
/>
|
|
108
|
+
</p>
|
|
109
|
+
<p align="center">
|
|
110
|
+
Copyright © 2025-present
|
|
111
|
+
<a href="https://github.com/y9c" target="_blank">Chang Y</a>
|
|
112
|
+
</p>
|
|
113
|
+
<p align="center">
|
|
114
|
+
<a href="https://github.com/y9c/countmut/blob/main/LICENSE">
|
|
115
|
+
<img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=282a36&colorB=c678dd" />
|
|
116
|
+
</a>
|
|
117
|
+
</p>
|
|
@@ -40,12 +40,8 @@ click.rich_click.TEXT_EMOJIS = True
|
|
|
40
40
|
click.rich_click.OPTION_GROUPS = {
|
|
41
41
|
"countmut": [
|
|
42
42
|
{
|
|
43
|
-
"name": "
|
|
44
|
-
"options": ["--input", "--reference"],
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"name": "Output Options",
|
|
48
|
-
"options": ["--output", "--save-rest", "--force"],
|
|
43
|
+
"name": "Input/Output Options",
|
|
44
|
+
"options": ["--input", "--reference", "--output", "--force"],
|
|
49
45
|
},
|
|
50
46
|
{
|
|
51
47
|
"name": "Mutation Analysis",
|
|
@@ -64,8 +60,12 @@ click.rich_click.OPTION_GROUPS = {
|
|
|
64
60
|
],
|
|
65
61
|
},
|
|
66
62
|
{
|
|
67
|
-
"name": "
|
|
68
|
-
"options": ["--pad"],
|
|
63
|
+
"name": "Output Records",
|
|
64
|
+
"options": ["--pad", "--save-rest"],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "Performance Options",
|
|
68
|
+
"options": ["--threads", "--bin-size"],
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
"name": "Help & Version",
|
|
@@ -181,7 +181,7 @@ countmut -i input.bam -r reference.fa --region chr1:1000000-2000000
|
|
|
181
181
|
"-s",
|
|
182
182
|
"--save-rest",
|
|
183
183
|
is_flag=True,
|
|
184
|
-
help="[bold]Save
|
|
184
|
+
help="[bold]Save other bases[/bold] statistics (o0, o1, o2 columns)",
|
|
185
185
|
)
|
|
186
186
|
@click.option(
|
|
187
187
|
"--region",
|
|
@@ -202,6 +202,7 @@ countmut -i input.bam -r reference.fa --region chr1:1000000-2000000
|
|
|
202
202
|
help="[bold]Strand processing[/bold]: 'both' (default), 'forward' (+ only), or 'reverse' (- only)",
|
|
203
203
|
)
|
|
204
204
|
@click.option(
|
|
205
|
+
"-p",
|
|
205
206
|
"--pad",
|
|
206
207
|
type=int,
|
|
207
208
|
default=15,
|
|
@@ -213,14 +214,14 @@ countmut -i input.bam -r reference.fa --region chr1:1000000-2000000
|
|
|
213
214
|
type=int,
|
|
214
215
|
default=2,
|
|
215
216
|
show_default=True,
|
|
216
|
-
help="[bold]Trim bases[/bold]
|
|
217
|
+
help="[bold]Trim N bases[/bold] from read 5' end (fragment orientation)",
|
|
217
218
|
)
|
|
218
219
|
@click.option(
|
|
219
220
|
"--trim-end",
|
|
220
221
|
type=int,
|
|
221
222
|
default=2,
|
|
222
223
|
show_default=True,
|
|
223
|
-
help="[bold]Trim bases[/bold]
|
|
224
|
+
help="[bold]Trim N bases[/bold] from read 3' end (fragment orientation)",
|
|
224
225
|
)
|
|
225
226
|
@click.option(
|
|
226
227
|
"--max-unc",
|
|
@@ -255,14 +255,14 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
255
255
|
for pos in target_sites_list:
|
|
256
256
|
position_data[pos] = {
|
|
257
257
|
"+": {
|
|
258
|
-
"
|
|
259
|
-
"
|
|
260
|
-
"
|
|
258
|
+
"high_conversion_count": Counter(),
|
|
259
|
+
"insufficient_conversion_count": Counter(),
|
|
260
|
+
"low_quality_count": Counter(),
|
|
261
261
|
},
|
|
262
262
|
"-": {
|
|
263
|
-
"
|
|
264
|
-
"
|
|
265
|
-
"
|
|
263
|
+
"high_conversion_count": Counter(),
|
|
264
|
+
"insufficient_conversion_count": Counter(),
|
|
265
|
+
"low_quality_count": Counter(),
|
|
266
266
|
},
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -310,10 +310,10 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
310
310
|
ns = read.get_tag("NS")
|
|
311
311
|
passes_mismatch_filter = ns <= max_sub
|
|
312
312
|
|
|
313
|
-
# Check conversion
|
|
313
|
+
# Check conversion filter (reads passing are sufficiently converted)
|
|
314
314
|
zf = read.get_tag("Zf")
|
|
315
315
|
yf = read.get_tag("Yf")
|
|
316
|
-
|
|
316
|
+
passes_conversion_filter = (zf <= max_unc) and (yf >= min_con)
|
|
317
317
|
|
|
318
318
|
# Process each position in the read
|
|
319
319
|
query_sequence = read.query_sequence
|
|
@@ -334,11 +334,23 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
334
334
|
continue
|
|
335
335
|
if query_pos >= len(query_sequence):
|
|
336
336
|
continue
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
)
|
|
337
|
+
|
|
338
|
+
# Check if position is internal (not in trimmed regions)
|
|
339
|
+
# Trim based on actual strand orientation (fragment 5' to 3')
|
|
340
|
+
# For forward strand (+): 5' is at start (low query_pos), 3' is at end (high query_pos)
|
|
341
|
+
# For reverse strand (-): 5' is at end (high query_pos), 3' is at start (low query_pos)
|
|
342
|
+
if actual_strand == "+":
|
|
343
|
+
# Forward: trim_start from 5' (beginning), trim_end from 3' (end)
|
|
344
|
+
is_internal = (
|
|
345
|
+
query_pos >= trim_start
|
|
346
|
+
and len(query_sequence) - query_pos > trim_end
|
|
347
|
+
)
|
|
348
|
+
else:
|
|
349
|
+
# Reverse: trim_start from 5' (end), trim_end from 3' (beginning)
|
|
350
|
+
is_internal = (
|
|
351
|
+
query_pos >= trim_end
|
|
352
|
+
and len(query_sequence) - query_pos > trim_start
|
|
353
|
+
)
|
|
342
354
|
# Get query base from read sequence (base_char is reference base, not query)
|
|
343
355
|
query_base = query_sequence[query_pos].upper()
|
|
344
356
|
base_qual = (
|
|
@@ -363,7 +375,7 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
363
375
|
bool(passes_mismatch_filter),
|
|
364
376
|
bool(passes_mapq_filter),
|
|
365
377
|
bool(passes_baseq_filter),
|
|
366
|
-
bool(
|
|
378
|
+
bool(passes_conversion_filter),
|
|
367
379
|
)
|
|
368
380
|
|
|
369
381
|
except (KeyError, AttributeError) as e:
|
|
@@ -380,28 +392,34 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
380
392
|
passes_mismatch_filter,
|
|
381
393
|
passes_mapq_filter,
|
|
382
394
|
passes_baseq_filter,
|
|
383
|
-
|
|
395
|
+
passes_conversion_filter,
|
|
384
396
|
) in best_obs.items():
|
|
385
397
|
# Skip positions that are not in our target sites (safety)
|
|
386
398
|
if ref_pos not in position_data:
|
|
387
399
|
continue
|
|
388
400
|
|
|
389
|
-
# Count in
|
|
401
|
+
# Count in low_quality if ANY quality filter fails
|
|
390
402
|
if not (
|
|
391
403
|
is_internal
|
|
392
404
|
and passes_mismatch_filter
|
|
393
405
|
and passes_mapq_filter
|
|
394
406
|
and passes_baseq_filter
|
|
395
407
|
):
|
|
396
|
-
position_data[ref_pos][strand_symbol]["
|
|
397
|
-
|
|
408
|
+
position_data[ref_pos][strand_symbol]["low_quality_count"][
|
|
409
|
+
query_base
|
|
410
|
+
] += 1
|
|
411
|
+
# Count in high_conversion/insufficient_conversion only if ALL quality filters pass
|
|
398
412
|
else:
|
|
399
|
-
if
|
|
400
|
-
|
|
413
|
+
if passes_conversion_filter:
|
|
414
|
+
# High conversion efficiency (pass quality + conversion filters)
|
|
415
|
+
position_data[ref_pos][strand_symbol]["high_conversion_count"][
|
|
401
416
|
query_base
|
|
402
417
|
] += 1
|
|
403
418
|
else:
|
|
404
|
-
|
|
419
|
+
# Insufficient conversion efficiency (pass quality but fail conversion)
|
|
420
|
+
position_data[ref_pos][strand_symbol][
|
|
421
|
+
"insufficient_conversion_count"
|
|
422
|
+
][query_base] += 1
|
|
405
423
|
|
|
406
424
|
# Calculate total skipped
|
|
407
425
|
total_skipped = (
|
|
@@ -433,9 +451,15 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
433
451
|
if process_reverse_only and strand_symbol != "-":
|
|
434
452
|
continue
|
|
435
453
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
454
|
+
high_conversion_count = position_data[pos][strand_symbol][
|
|
455
|
+
"high_conversion_count"
|
|
456
|
+
]
|
|
457
|
+
insufficient_conversion_count = position_data[pos][strand_symbol][
|
|
458
|
+
"insufficient_conversion_count"
|
|
459
|
+
]
|
|
460
|
+
low_quality_count = position_data[pos][strand_symbol][
|
|
461
|
+
"low_quality_count"
|
|
462
|
+
]
|
|
439
463
|
|
|
440
464
|
# Get motif
|
|
441
465
|
motif = extended_target_seq[
|
|
@@ -448,15 +472,15 @@ def parse_region_worker(args: tuple) -> dict[str, Any]:
|
|
|
448
472
|
|
|
449
473
|
# Calculate counts
|
|
450
474
|
# u = unconverted (reference base), m = mutation (mutation base only), o = others
|
|
451
|
-
u0 =
|
|
452
|
-
m0 =
|
|
453
|
-
o0 =
|
|
454
|
-
u1 =
|
|
455
|
-
m1 =
|
|
456
|
-
o1 =
|
|
457
|
-
u2 =
|
|
458
|
-
m2 =
|
|
459
|
-
o2 =
|
|
475
|
+
u0 = low_quality_count[ref_base]
|
|
476
|
+
m0 = low_quality_count[mut_base]
|
|
477
|
+
o0 = low_quality_count.total() - u0 - m0
|
|
478
|
+
u1 = high_conversion_count[ref_base]
|
|
479
|
+
m1 = high_conversion_count[mut_base]
|
|
480
|
+
o1 = high_conversion_count.total() - u1 - m1
|
|
481
|
+
u2 = insufficient_conversion_count[ref_base]
|
|
482
|
+
m2 = insufficient_conversion_count[mut_base]
|
|
483
|
+
o2 = insufficient_conversion_count.total() - u2 - m2
|
|
460
484
|
|
|
461
485
|
if u1 + m1 + u2 + m2 > 0:
|
|
462
486
|
site_info = [region_chrom, pos + 1, strand_symbol, motif]
|
|
@@ -534,8 +558,8 @@ def count_mutations(
|
|
|
534
558
|
save_rest: Whether to save additional statistics (default: False)
|
|
535
559
|
region: Genomic region to process (e.g., 'chr1:1000000-2000000')
|
|
536
560
|
pad: Motif half-window padding around site (default: 15)
|
|
537
|
-
trim_start:
|
|
538
|
-
trim_end:
|
|
561
|
+
trim_start: Number of bases to trim from read 5' end (fragment orientation) (default: 2)
|
|
562
|
+
trim_end: Number of bases to trim from read 3' end (fragment orientation) (default: 2)
|
|
539
563
|
max_unc: Max unconverted threshold (Zf) to consider converted (default: 3)
|
|
540
564
|
min_con: Min converted threshold (Yf) to consider converted (default: 1)
|
|
541
565
|
max_sub: Max substitutions (NS) to consider mapped (default: 1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: countmut
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Ultra-fast strand-aware mutation counter
|
|
5
5
|
Author-email: Ye Chang <yech1990@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,13 +41,13 @@ Dynamic: license-file
|
|
|
41
41
|
[](https://pepy.tech/project/countmut)
|
|
42
42
|
[](https://github.com/y9c/countmut)
|
|
43
43
|
|
|
44
|
-
**Ultra-fast strand-aware mutation counter**
|
|
44
|
+
> **Ultra-fast strand-aware mutation counter for bisulfite sequencing analysis**
|
|
45
45
|
|
|
46
|
-
CountMut
|
|
46
|
+
CountMut is a high-performance tool for counting mutations from bisulfite sequencing BAM files (BS-seq, CAM-seq, GLORI-seq, eTAM-seq). It features parallel processing, quality-based mate overlap deduplication, and optimized file I/O for maximum speed.
|
|
47
47
|
|
|
48
48
|
## Features
|
|
49
49
|
|
|
50
|
-
- 🚀 **Ultra-Fast**:
|
|
50
|
+
- 🚀 **Ultra-Fast**: Call mutation without pileup reads
|
|
51
51
|
- 🧬 **Bisulfite Support**: NS, Zf, Yf tag filtering for conversion analysis
|
|
52
52
|
- 🎯 **Accurate**: Quality-based mate overlap deduplication prevents double-counting
|
|
53
53
|
- ⚡ **Parallel**: Multi-threaded genomic window processing
|
|
@@ -72,51 +72,68 @@ countmut -i input.bam -r reference.fa -o mutations.tsv --ref-base T --mut-base C
|
|
|
72
72
|
countmut -i input.bam -r reference.fa -o mutations.tsv -t 8 --max-unc 5 --min-con 2
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
##
|
|
75
|
+
## Options
|
|
76
76
|
|
|
77
|
+
**Input/Output**
|
|
77
78
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Output:
|
|
83
|
-
-o, --output PATH Output TSV file (default: stdout)
|
|
84
|
-
|
|
85
|
-
Mutation:
|
|
86
|
-
--ref-base TEXT Reference base [default: A]
|
|
87
|
-
--mut-base TEXT Mutation base [default: G]
|
|
88
|
-
--strand [both|forward|reverse] Strand processing [default: both]
|
|
89
|
-
--region TEXT Specific region (e.g., 'chr1:1000000-2000000')
|
|
90
|
-
|
|
91
|
-
Performance:
|
|
92
|
-
-t, --threads INTEGER Number of threads [default: auto]
|
|
93
|
-
-b, --bin-size INTEGER Genomic bin size [default: 10000]
|
|
94
|
-
|
|
95
|
-
Filtering (Bisulfite):
|
|
96
|
-
--pad INTEGER Motif window padding [default: 15]
|
|
97
|
-
--trim-start INTEGER Trim 5' bases [default: 2]
|
|
98
|
-
--trim-end INTEGER Trim 3' bases [default: 2]
|
|
99
|
-
--max-unc INTEGER Max unconverted (Zf) [default: 3]
|
|
100
|
-
--min-con INTEGER Min converted (Yf) [default: 1]
|
|
101
|
-
--max-sub INTEGER Max substitutions (NS) [default: 1]
|
|
102
|
-
--min-baseq INTEGER Min base quality (Phred) [default: 20]
|
|
103
|
-
--min-mapq INTEGER Min mapping quality (MAPQ) [default: 0]
|
|
79
|
+
-i, --input PATH Input BAM file (coordinate-sorted) [required]
|
|
80
|
+
-r, --reference PATH Reference FASTA file [required]
|
|
81
|
+
-o, --output PATH Output TSV file (default: stdout)
|
|
82
|
+
-f, --force Overwrite output without prompting
|
|
104
83
|
```
|
|
105
84
|
|
|
106
|
-
**
|
|
85
|
+
**Mutation Analysis**
|
|
86
|
+
```bash
|
|
87
|
+
--ref-base TEXT Reference base to count from [default: A]
|
|
88
|
+
--mut-base TEXT Mutation base to count [default: G]
|
|
89
|
+
--strand TEXT Strand: both/forward/reverse [default: both]
|
|
90
|
+
--region TEXT Genomic region (e.g., 'chr1:1000000-2000000')
|
|
91
|
+
```
|
|
107
92
|
|
|
108
|
-
|
|
93
|
+
**Performance**
|
|
94
|
+
```bash
|
|
95
|
+
-t, --threads INTEGER Number of parallel threads [default: auto]
|
|
96
|
+
-b, --bin-size INTEGER Genomic bin size in bp [default: 10000]
|
|
97
|
+
```
|
|
109
98
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
99
|
+
**Quality Filters**
|
|
100
|
+
```bash
|
|
101
|
+
--min-baseq INTEGER Min base quality (Phred score) [default: 20]
|
|
102
|
+
--min-mapq INTEGER Min mapping quality (MAPQ) [default: 0]
|
|
103
|
+
--max-sub INTEGER Max substitutions (NS tag) [default: 1]
|
|
104
|
+
--trim-start INTEGER Trim N bases from read 5' end (fragment orientation) [default: 2]
|
|
105
|
+
--trim-end INTEGER Trim N bases from read 3' end (fragment orientation) [default: 2]
|
|
106
|
+
--max-unc INTEGER Max unconverted (Zf tag) [default: 3]
|
|
107
|
+
--min-con INTEGER Min converted (Yf tag) [default: 1]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Output Records**
|
|
111
|
+
```bash
|
|
112
|
+
-p, --pad INTEGER Motif window half-size [default: 15]
|
|
113
|
+
-s, --save-rest Include other bases (o0, o1, o2 columns)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> **Note**: BAM files must have **NS**, **Zf**, and **Yf** tags (essential for bisulfite analysis).
|
|
117
|
+
> Indices (.bai, .fai) are created automatically if missing.
|
|
118
|
+
|
|
119
|
+
## Output Format
|
|
115
120
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
TSV file with the following columns:
|
|
122
|
+
|
|
123
|
+
| Column | Description |
|
|
124
|
+
|--------|-------------|
|
|
125
|
+
| `chrom` | Chromosome name |
|
|
126
|
+
| `pos` | Genomic position (1-based) |
|
|
127
|
+
| `strand` | Strand (+ or -) |
|
|
128
|
+
| `motif` | Sequence context (2×pad+1 bp window) |
|
|
129
|
+
| `u0`, `u1`, `u2` | **Unconverted** (reference base) counts |
|
|
130
|
+
| `m0`, `m1`, `m2` | **Mutation** (mutation base only) counts |
|
|
131
|
+
| `o0`, `o1`, `o2` | **Other bases** counts (with `--save-rest`) |
|
|
132
|
+
|
|
133
|
+
**Count categories** (x0, x1, x2):
|
|
134
|
+
- **x0 (low quality)**: Bases failing quality filters (trim region, max-sub, min-mapq, min-baseq)
|
|
135
|
+
- **x1 (high conversion)**: Bases from reads with high conversion efficiency (low Zf and high Yf)
|
|
136
|
+
- **x2 (insufficient conversion)**: Bases from reads with insufficient conversion efficiency (high Zf or low Yf)
|
|
120
137
|
|
|
121
138
|
|
|
122
139
|
|
countmut-0.0.2/README.md
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# CountMut
|
|
2
|
-
|
|
3
|
-
[](https://pypi.python.org/pypi/countmut)
|
|
4
|
-
[](https://pepy.tech/project/countmut)
|
|
5
|
-
[](https://github.com/y9c/countmut)
|
|
6
|
-
|
|
7
|
-
**Ultra-fast strand-aware mutation counter**
|
|
8
|
-
|
|
9
|
-
CountMut counts mutations from bisulfite sequencing / CAM-seq / GLORI-seq / eTAM-seq BAM files with parallel processing, quality-based mate overlap deduplication, and optimized file I/O.
|
|
10
|
-
|
|
11
|
-
## Features
|
|
12
|
-
|
|
13
|
-
- 🚀 **Ultra-Fast**: Direct FASTA index reading, shared file handles, BGZF multi-threading
|
|
14
|
-
- 🧬 **Bisulfite Support**: NS, Zf, Yf tag filtering for conversion analysis
|
|
15
|
-
- 🎯 **Accurate**: Quality-based mate overlap deduplication prevents double-counting
|
|
16
|
-
- ⚡ **Parallel**: Multi-threaded genomic window processing
|
|
17
|
-
- 🔧 **Flexible**: Configurable filtering, strand-specific processing, auto-indexing
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
pip install countmut
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Quick Start
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# Basic usage - auto-creates indices if needed
|
|
29
|
-
countmut -i input.bam -r reference.fa -o mutations.tsv
|
|
30
|
-
|
|
31
|
-
# Count T→C mutations (common in bisulfite sequencing)
|
|
32
|
-
countmut -i input.bam -r reference.fa -o mutations.tsv --ref-base T --mut-base C
|
|
33
|
-
|
|
34
|
-
# With custom threads and filtering
|
|
35
|
-
countmut -i input.bam -r reference.fa -o mutations.tsv -t 8 --max-unc 5 --min-con 2
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Key Options
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
Required:
|
|
42
|
-
-i, --input PATH Input BAM file
|
|
43
|
-
-r, --reference PATH Reference FASTA file
|
|
44
|
-
|
|
45
|
-
Output:
|
|
46
|
-
-o, --output PATH Output TSV file (default: stdout)
|
|
47
|
-
|
|
48
|
-
Mutation:
|
|
49
|
-
--ref-base TEXT Reference base [default: A]
|
|
50
|
-
--mut-base TEXT Mutation base [default: G]
|
|
51
|
-
--strand [both|forward|reverse] Strand processing [default: both]
|
|
52
|
-
--region TEXT Specific region (e.g., 'chr1:1000000-2000000')
|
|
53
|
-
|
|
54
|
-
Performance:
|
|
55
|
-
-t, --threads INTEGER Number of threads [default: auto]
|
|
56
|
-
-b, --bin-size INTEGER Genomic bin size [default: 10000]
|
|
57
|
-
|
|
58
|
-
Filtering (Bisulfite):
|
|
59
|
-
--pad INTEGER Motif window padding [default: 15]
|
|
60
|
-
--trim-start INTEGER Trim 5' bases [default: 2]
|
|
61
|
-
--trim-end INTEGER Trim 3' bases [default: 2]
|
|
62
|
-
--max-unc INTEGER Max unconverted (Zf) [default: 3]
|
|
63
|
-
--min-con INTEGER Min converted (Yf) [default: 1]
|
|
64
|
-
--max-sub INTEGER Max substitutions (NS) [default: 1]
|
|
65
|
-
--min-baseq INTEGER Min base quality (Phred) [default: 20]
|
|
66
|
-
--min-mapq INTEGER Min mapping quality (MAPQ) [default: 0]
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Note**: BAM must have NS, Zf, and Yf tags for bisulfite analysis.
|
|
70
|
-
|
|
71
|
-
## Output Format
|
|
72
|
-
|
|
73
|
-
TSV file with columns:
|
|
74
|
-
- `chrom`, `pos`, `strand`, `motif` - Position and sequence context
|
|
75
|
-
- `u0`, `u1`, `u2` - Unconverted (reference base) counts [drop, clean, unconverted]
|
|
76
|
-
- `m0`, `m1`, `m2` - Mutation (mutation base only) counts [drop, clean, unconverted]
|
|
77
|
-
- `o0`, `o1`, `o2` - Other bases counts [drop, clean, unconverted] (only with `--save-rest`)
|
|
78
|
-
|
|
79
|
-
Where:
|
|
80
|
-
- **drop** (x0): Bases failing quality filters (internal position, mismatch, mapq, baseq)
|
|
81
|
-
- **clean** (x1): High-quality bases passing all filters
|
|
82
|
-
- **unconverted** (x2): Bases in unconverted reads (high Zf or low Yf)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<p align="center">
|
|
88
|
-
<img
|
|
89
|
-
src="https://raw.githubusercontent.com/y9c/y9c/master/resource/footer_line.svg?sanitize=true"
|
|
90
|
-
/>
|
|
91
|
-
</p>
|
|
92
|
-
<p align="center">
|
|
93
|
-
Copyright © 2025-present
|
|
94
|
-
<a href="https://github.com/y9c" target="_blank">Chang Y</a>
|
|
95
|
-
</p>
|
|
96
|
-
<p align="center">
|
|
97
|
-
<a href="https://github.com/y9c/countmut/blob/main/LICENSE">
|
|
98
|
-
<img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=282a36&colorB=c678dd" />
|
|
99
|
-
</a>
|
|
100
|
-
</p>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|