Skip to content

Commit 640f88b

Browse files
authored
feat(xxej-scanner): implement first complete scanner package
Implement the first complete XXEJ scanner package for CUT&Tag-enriched paired-end BAM analysis. This adds the uv-packaged Python project, CLI entry points, shared data models, input validation, BAM and reference helpers, coverage-based candidate region discovery, breakpoint clustering, repair-event classification, genotype-support estimation, second-pass validation, and structured output writers. The scanner reports candidate DSB repair-associated events from clipped reads, CIGAR indels, SA-tag split reads, discordant pairs, and local reference context. Reference-sequence helpers include microhomology detection for the canonical L-m-X-m-R -> L-m-R deletion model by comparing the upstream flank of bkp_a with the downstream flank of bkp_b. The README documents installation, uv-based execution, required inputs, example scan commands, generated outputs, supported event types, and interpretation notes for repair evidence fractions in CUT&Tag-enriched data.
2 parents 44cbfac + 022885a commit 640f88b

17 files changed

Lines changed: 2777 additions & 0 deletions

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.venv/
2+
venv/
3+
__pycache__/
4+
*.py[cod]
5+
build/
6+
dist/
7+
*.egg-info/
8+
.coverage
9+
.pytest_cache/

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,125 @@
11
# XXEJ_scanner
22

33
`XXEJ_scanner` is a first-version, rule-based scanner for LIG3/LIG4 CUT&Tag-enriched paired-end BAM files. It reports candidate DSB repair-associated events rather than definitive structural variants.
4+
5+
The pipeline keeps three concepts separate:
6+
7+
1. CUT&Tag-enriched candidate regions from coverage or user BED input.
8+
2. Breakpoint clusters from local soft-clipped read ends.
9+
3. Candidate repair events supported by clipped reads, CIGAR indels, SA-tag split reads, and discordant pairs.
10+
11+
## Install
12+
13+
This repository is a `uv` project. From the project root:
14+
15+
```bash
16+
uv sync --no-editable
17+
```
18+
19+
Run the scanner through the installed console script:
20+
21+
```bash
22+
uv run --no-editable XXEJ_scanner --help
23+
uv run --no-editable XXEJ_scanner scan --help
24+
```
25+
26+
The lowercase alias is also available:
27+
28+
```bash
29+
uv run --no-editable xxej-scanner scan --help
30+
```
31+
32+
## Inputs
33+
34+
Required:
35+
36+
```bash
37+
--treated-bam sample.sorted.bam
38+
--reference-fasta genome.fa
39+
--output-dir results/XXEJ_scanner
40+
```
41+
42+
Optional:
43+
44+
```bash
45+
--control-bam control.sorted.bam
46+
--candidate-bed candidates.bed
47+
--peak-bed peaks.bed
48+
--sample-name treated
49+
--control-name control
50+
```
51+
52+
BAM and FASTA indexes are required. Missing `.bai`/`.csi` or `.fai` files are reported as errors.
53+
54+
## Example
55+
56+
```bash
57+
uv run --no-editable XXEJ_scanner scan \
58+
--treated-bam bam/090-ETO-L189.sorted.bam \
59+
--control-bam bam/090-control.sorted.bam \
60+
--reference-fasta ref/genome.fa \
61+
--output-dir results/XXEJ_scanner \
62+
--min-mapq 20 \
63+
--min-clip-length 10 \
64+
--clip-cluster-window 20 \
65+
--coverage-bin-size 100 \
66+
--merge-distance 300 \
67+
--min-alt-support 3
68+
```
69+
70+
With a candidate BED:
71+
72+
```bash
73+
uv run --no-editable XXEJ_scanner scan \
74+
--treated-bam bam/090-ETO-L189.sorted.bam \
75+
--control-bam bam/090-control.sorted.bam \
76+
--reference-fasta ref/genome.fa \
77+
--candidate-bed peaks/union_candidates.bed \
78+
--output-dir results/XXEJ_scanner
79+
```
80+
81+
## Outputs
82+
83+
The output directory contains:
84+
85+
```text
86+
candidate_regions.bed
87+
breakpoint_clusters.tsv
88+
events.tsv
89+
event_evidence.tsv
90+
run_summary.json
91+
raw_clip_sites.tsv
92+
raw_discordant_pairs.tsv
93+
raw_split_reads.tsv
94+
igv_loci.bed
95+
```
96+
97+
Coordinates are 0-based half-open for BED-like intervals. Breakpoint positions are reported as 0-based reference positions derived from alignment starts for left clips and alignment ends for right clips.
98+
99+
## Event Types
100+
101+
`NHEJ_INS` marks a candidate local end-joining event with small inserted or filler sequence evidence near a clipped breakpoint.
102+
103+
`MMEJ_DEL` marks a candidate local deletion event with paired local breakpoint evidence and reference microhomology context.
104+
105+
`NHEJ_BND_INS_INTRA` and `NHEJ_BND_INS_INTER` mark candidate wrong-end joining supported by local clipping plus distant same-chromosome or inter-chromosome split/paired evidence.
106+
107+
## repair_evidence_fraction
108+
109+
`repair_evidence_fraction` is:
110+
111+
```text
112+
ALT-like support / (ALT-like support + REF-like support)
113+
```
114+
115+
ALT-like support includes breakpoint-associated clipping, SA-tag split reads, discordant pairs, and local CIGAR insertion/deletion evidence. REF-like support includes reads spanning the candidate breakpoint or interval without strong clipping and with locally consistent alignment.
116+
117+
Because this is CUT&Tag-enriched data, this value is an enrichment-data-derived evidence fraction. It should not be interpreted as a true WGS allele fraction or VAF.
118+
119+
## Difference From WGS SV Callers
120+
121+
The scanner does not assume uniform whole-genome coverage and does not call repair events from coverage alone. Coverage only defines candidate enriched regions. Breakpoint and event calls require local clipped, indel, split-read, or paired-end evidence.
122+
123+
## Difference From MEIGA-SR
124+
125+
MEIGA-SR uses REF/ALT logic for mobile element insertion genotyping. Here, `REF-like` means intact local spanning evidence around a candidate DSB breakpoint, while `ALT-like` means evidence supporting a repair-associated abnormal structure.

pyproject.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[project]
2+
name = "xxej-scanner"
3+
version = "0.1.0"
4+
description = "Rule-based scanner for CUT&Tag-enriched XXEJ repair-associated events."
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
dependencies = [
8+
"pysam>=0.22.0",
9+
]
10+
11+
[project.scripts]
12+
XXEJ_scanner = "XXEJ_scanner.cli:main"
13+
xxej-scanner = "XXEJ_scanner.cli:main"
14+
15+
[build-system]
16+
requires = ["hatchling>=1.27"]
17+
build-backend = "hatchling.build"
18+
19+
[tool.hatch.build.targets.wheel]
20+
packages = ["src/XXEJ_scanner"]
21+
22+
[tool.uv]
23+
package = true

src/XXEJ_scanner/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""CUT&Tag-enriched XXEJ repair outcome scanner."""
2+
3+
__all__ = ["__version__"]
4+
5+
__version__ = "0.1.0"

0 commit comments

Comments
 (0)