Skip to content

Commit 57f4db1

Browse files
committed
.
1 parent dfe16cf commit 57f4db1

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

recmpox/recmpox.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,7 @@ def _extract_tract_sequences(
14191419
alignments_queries: Dict[str, str],
14201420
ref1_label: str,
14211421
ref2_label: str,
1422+
is_intra_clade: bool,
14221423
min_consecutive: int = 1,
14231424
line_len: int = 80,
14241425
include_indels: bool = False,
@@ -1436,6 +1437,14 @@ def _extract_tract_sequences(
14361437
14371438
Tract boundaries use all positions in each sample's allegiances (including
14381439
indel columns when -include-indels was used). Clade labels: ``"ia"`` (ref1), ``"ib"`` (ref2).
1440+
When is_intra_clade is True (e.g. Ia vs Ib or IIa vs IIb), we keep "all
1441+
non-opposite" bases for each clade (Ia tract = not Ib; Ib tract = not Ia),
1442+
so ambiguous/other positions remain in both masked sequences.
1443+
1444+
When is_intra_clade is False (inter-clade, e.g. I vs II), we only keep
1445+
positions confidently assigned to that clade (strict tracts) using
1446+
_extract_tracts_as_n_full_length, so masked sequences contain only Ia or
1447+
only Ib tract positions and everything else becomes N.
14391448
"""
14401449
out_dir.mkdir(parents=True, exist_ok=True)
14411450
ref1_out = out_dir / f"{ref1_label}_recombinant_ancestral_tract.fa"
@@ -1466,18 +1475,28 @@ def _extract_tract_sequences(
14661475
n_skip_no_seq += 1
14671476
continue
14681477

1469-
# ref1 (Ia) file: keep clade I bases and all positions not confidently Ib.
1470-
# ref2 (Ib) file: keep clade IIb bases and all positions not confidently Ia.
14711478
safe_id = _safe_fasta_id(sample_id)
1472-
seq1 = _extract_full_length_non_opposite(aligned_seq, allegiances, keep_clade="ia")
1479+
# ref1 (Ia) file
1480+
if is_intra_clade:
1481+
# Intra-clade: keep clade Ia bases and all positions not confidently Ib.
1482+
seq1 = _extract_full_length_non_opposite(aligned_seq, allegiances, keep_clade="ia")
1483+
else:
1484+
# Inter-clade: strict Ia tracts only (Ia bases; everything else → N).
1485+
seq1 = _extract_tracts_as_n_full_length(aligned_seq, merged_tracts, keep_clade="ia")
14731486
len1 = len(seq1)
14741487
non_n1 = sum(1 for b in seq1.upper() if b in "ACGT")
14751488
cov1 = (100.0 * non_n1 / len1) if len1 else 0.0
14761489
fh1.write(f">{safe_id}_{ref1_label}_tract_HC_{cov1:.2f}%\n")
14771490
for i in range(0, len1, line_len):
14781491
fh1.write(seq1[i : i + line_len] + "\n")
14791492

1480-
seq2 = _extract_full_length_non_opposite(aligned_seq, allegiances, keep_clade="ib")
1493+
# ref2 (Ib/IIb) file
1494+
if is_intra_clade:
1495+
# Intra-clade: keep clade Ib bases and all positions not confidently Ia.
1496+
seq2 = _extract_full_length_non_opposite(aligned_seq, allegiances, keep_clade="ib")
1497+
else:
1498+
# Inter-clade: strict Ib/IIb tracts only.
1499+
seq2 = _extract_tracts_as_n_full_length(aligned_seq, merged_tracts, keep_clade="ib")
14811500
len2 = len(seq2)
14821501
non_n2 = sum(1 for b in seq2.upper() if b in "ACGT")
14831502
cov2 = (100.0 * non_n2 / len2) if len2 else 0.0
@@ -3596,6 +3615,7 @@ def row(r: Dict[str, Any]) -> str:
35963615
alignments_queries=alignments_queries,
35973616
ref1_label=ref1_label,
35983617
ref2_label=ref2_label,
3618+
is_intra_clade=is_intra_clade,
35993619
min_consecutive=int(getattr(args, "breakpoint_min_snps", 1)),
36003620
include_indels=getattr(args, "include_indels", False),
36013621
)

0 commit comments

Comments
 (0)