Skip to content

Commit a8d63a7

Browse files
committed
Update tests, fix some paired logic
1 parent 84279af commit a8d63a7

2 files changed

Lines changed: 350 additions & 107 deletions

File tree

align_trim/main.py

Lines changed: 102 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def trim(segment, primer_pos, end, verbose=False):
182182

183183
# softmask the left primer
184184
if not end:
185-
# update the position of the leftmost mappinng base
185+
# update the position of the leftmost mapping base
186186
segment.pos = pos - extra
187187
if verbose:
188188
print(
@@ -342,19 +342,34 @@ def handle_segments(
342342
)
343343
else:
344344
# locate the nearest primers to this alignment segment pair
345-
p1 = find_primer_with_lookup(
346-
lookup=lookup,
347-
pos=segment1.reference_start,
348-
direction="+",
349-
chrom=segment1.reference_name,
350-
)
351-
352-
p2 = find_primer_with_lookup(
353-
lookup=lookup,
354-
pos=segment2.reference_end,
355-
direction="-",
356-
chrom=segment2.reference_name,
357-
)
345+
if segment1.reference_start < segment2.reference_start:
346+
# if segment1 starts before segment2, then segment1 is the left segment relative to the reference
347+
p1 = find_primer_with_lookup(
348+
lookup=lookup,
349+
pos=segment1.reference_start,
350+
direction="+",
351+
chrom=segment1.reference_name,
352+
)
353+
p2 = find_primer_with_lookup(
354+
lookup=lookup,
355+
pos=segment2.reference_end,
356+
direction="-",
357+
chrom=segment2.reference_name,
358+
)
359+
else:
360+
# otherwise then segment2 is the left segment relative to the reference
361+
p1 = find_primer_with_lookup(
362+
lookup=lookup,
363+
pos=segment2.reference_start,
364+
direction="+",
365+
chrom=segment2.reference_name,
366+
)
367+
p2 = find_primer_with_lookup(
368+
lookup=lookup,
369+
pos=segment1.reference_end,
370+
direction="-",
371+
chrom=segment1.reference_name,
372+
)
358373

359374
if not p1 or not p2:
360375
segment = segment1 if segment1 else segment2
@@ -366,8 +381,6 @@ def handle_segments(
366381
return False
367382

368383
# check if primers are correctly paired and then assign read group
369-
# NOTE: removed this as a function as only called once
370-
# TODO: will try improving this / moving it to the primer scheme processing code
371384
correctly_paired = p1.amplicon_number == p2.amplicon_number
372385

373386
if not paired:
@@ -469,15 +482,14 @@ def handle_segments(
469482
return False
470483

471484
# Check require-full-length
472-
if not paired:
473-
if args.require_full_length:
474-
if segment.reference_start > p1.end or segment.reference_end < p2.start:
475-
if args.verbose:
476-
print(
477-
f"{segment.query_name}: ref_start {segment.reference_start} > p1.end {p1.end} or ref_end {segment.reference_end} < p2.start {p2.start}, does not span a full amplicon, skipping",
478-
file=sys.stderr,
479-
)
480-
return False
485+
if args.require_full_length:
486+
if segment.reference_start > p1.end or segment.reference_end < p2.start:
487+
if args.verbose:
488+
print(
489+
f"{segment.query_name}: ref_start {segment.reference_start} > p1.end {p1.end} or ref_end {segment.reference_end} < p2.start {p2.start}, does not span a full amplicon, skipping",
490+
file=sys.stderr,
491+
)
492+
return False
481493

482494
# If not normalising, write the segment to the output file and add it to amplicon depth numpy array
483495
if not args.normalise:
@@ -496,65 +508,46 @@ def handle_segments(
496508
return (amplicon, segment)
497509

498510
else:
499-
if segment1.reference_start < p1_position:
500-
try:
501-
trim(segment1, p1_position, False, args.verbose)
502-
if args.verbose:
503-
print(
504-
f"{segment1.query_name}: ref start {segment1.reference_start} >= primer_position {p1_position}",
505-
file=sys.stderr,
511+
for segment_of_pair in (segment1, segment2):
512+
if segment_of_pair.reference_start < p1_position:
513+
try:
514+
trim(
515+
segment_of_pair,
516+
p1_position,
517+
segment_of_pair.is_reverse,
518+
args.verbose,
506519
)
507-
except Exception as e:
508-
print(
509-
f"{segment1.query_name}: Problem soft masking left primer (error: {e}), skipping",
510-
file=sys.stderr,
511-
)
512-
return False
513-
514-
elif segment1.reference_end > p2_position: # type: ignore
515-
try:
516-
trim(segment1, p2_position, True, args.verbose)
517-
if args.verbose:
520+
if args.verbose:
521+
print(
522+
f"{segment_of_pair.query_name}: ref start {segment_of_pair.reference_start} >= primer_position {p1_position}",
523+
file=sys.stderr,
524+
)
525+
except Exception as e:
518526
print(
519-
f"{segment1.query_name}: ref_end {segment1.reference_end} >= primer_position {p2_position}",
527+
f"{segment_of_pair.query_name}: Problem soft masking left primer (error: {e}), skipping",
520528
file=sys.stderr,
521529
)
522-
except Exception as e:
523-
print(
524-
f"{segment1.query_name}: Problem soft masking right primer (error: {e}), skipping",
525-
file=sys.stderr,
526-
)
527-
return False
530+
return False
528531

529-
# softmask the alignment if right primer start/end inside alignment
530-
if segment2.reference_end > p2_position: # type: ignore
531-
try:
532-
trim(segment2, p2_position, True, args.verbose)
533-
if args.verbose:
534-
print(
535-
f"{segment1.query_name}: ref_start {segment2.reference_start} >= primer_position {p2_position}",
536-
file=sys.stderr,
532+
if segment_of_pair.reference_end > p2_position: # type: ignore
533+
try:
534+
trim(
535+
segment_of_pair,
536+
p2_position,
537+
segment_of_pair.is_reverse,
538+
args.verbose,
537539
)
538-
except Exception as e:
539-
print(
540-
f"{segment1.query_name}: Problem soft masking right primer (error: {e}), skipping",
541-
file=sys.stderr,
542-
)
543-
return False
544-
elif segment2.reference_start < p1_position:
545-
try:
546-
trim(segment2, p1_position, False, args.verbose)
547-
if args.verbose:
540+
if args.verbose:
541+
print(
542+
f"{segment_of_pair.query_name}: ref_end {segment_of_pair.reference_end} >= primer_position {p2_position}",
543+
file=sys.stderr,
544+
)
545+
except Exception as e:
548546
print(
549-
f"{segment1.query_name}: ref_end {segment2.reference_end} >= primer_position {p1_position}",
547+
f"{segment_of_pair.query_name}: Problem soft masking right primer (error: {e}), skipping",
550548
file=sys.stderr,
551549
)
552-
except Exception as e:
553-
print(
554-
f"{segment1.query_name}: Problem soft masking left primer (error: {e}), skipping",
555-
file=sys.stderr,
556-
)
557-
return False
550+
return False
558551

559552
# check the the alignment still contains bases matching the reference
560553
if "M" not in segment1.cigarstring or "M" not in segment2.cigarstring: # type: ignore
@@ -566,33 +559,40 @@ def handle_segments(
566559
return False
567560

568561
if args.require_full_length:
569-
if segment1.reference_start > p1.end or segment2.reference_end < p2.start:
570-
if args.verbose:
571-
print(
572-
f"{segment1.query_name}: ref_start {segment1.reference_start} > p1.end {p1.end} or ref_end {segment2.reference_end} < p2.start {p2.start}, does not span a full amplicon, skipping",
573-
file=sys.stderr,
574-
)
575-
return False
562+
if segment1.reference_start < segment2.reference_start:
563+
if (
564+
segment1.reference_start > p1.end
565+
or segment2.reference_end < p2.start
566+
):
567+
if args.verbose:
568+
print(
569+
f"{segment1.query_name}: ref_start {segment1.reference_start} > p1.end {p1.end} or ref_end {segment2.reference_end} < p2.start {p2.start}, does not span a full amplicon, skipping",
570+
file=sys.stderr,
571+
)
572+
return False
573+
else:
574+
if (
575+
segment2.reference_start > p1.end
576+
or segment1.reference_end < p2.start
577+
):
578+
if args.verbose:
579+
print(
580+
f"{segment1.query_name}: ref_end {segment1.reference_end} < p1.start {p1.start} or ref_start {segment2.reference_start} > p2.end {p2.end}, does not span a full amplicon, skipping",
581+
file=sys.stderr,
582+
)
583+
return False
576584

577585
# If not normalising, write the segments to the output file and add them to amplicon depth numpy array
578586
if not args.normalise:
579587
outfile_writer.write(segment1)
580588
outfile_writer.write(segment2)
581-
segment1_amp_relative_start = segment1.reference_start - p1.start
582-
segment1_amp_relative_end = segment1.reference_end - p1.start
583-
if segment1_amp_relative_start < 0:
584-
segment1_amp_relative_start = 0
585-
586-
segment2_amp_relative_start = segment2.reference_start - p1.start
587-
segment2_amp_relative_end = segment2.reference_end - p1.start
588-
if segment2_amp_relative_start < 0:
589-
segment2_amp_relative_start = 0
590-
589+
for segment_in_pair in (segment1, segment2):
590+
segment_amp_relative_start = segment_in_pair.reference_start - p1.start
591+
segment_amp_relative_end = segment_in_pair.reference_end - p1.start
592+
if segment_amp_relative_start < 0:
593+
segment_amp_relative_start = 0
591594
amp_depths[segment1.reference_name][amplicon][
592-
segment1_amp_relative_start:segment1_amp_relative_end
593-
] += 1
594-
amp_depths[segment2.reference_name][amplicon][
595-
segment2_amp_relative_start:segment2_amp_relative_end
595+
segment_amp_relative_start:segment_amp_relative_end
596596
] += 1
597597

598598
return (amplicon, False)
@@ -813,8 +813,8 @@ def go(args):
813813
pools_str.add("unmatched")
814814

815815
# open the input samfile and process read groups
816-
if args.bamfile and args.bamfile != "-":
817-
infile = pysam.AlignmentFile(args.bamfile, "rb")
816+
if args.samfile and args.samfile != "-":
817+
infile = pysam.AlignmentFile(args.samfile, "rb")
818818
else:
819819
infile = pysam.AlignmentFile("-", "rb")
820820

@@ -1034,7 +1034,7 @@ def go(args):
10341034

10351035
def main():
10361036
parser = argparse.ArgumentParser(
1037-
description="Trim alignments from an amplicon scheme. Bam (input) can be provided by --bamfile or stdin"
1037+
description="Trim alignments from an amplicon scheme. Bam (input) can be provided by --samfile or stdin"
10381038
)
10391039
parser.add_argument(
10401040
"bedfile",
@@ -1043,9 +1043,9 @@ def main():
10431043
metavar="BEDFILE",
10441044
)
10451045
parser.add_argument(
1046-
"--bamfile",
1047-
"-b",
1048-
help="Sorted BAM file containing the aligned reads, if this is not provided (or '-') then 'align_trim' will read from stdin.",
1046+
"--samfile",
1047+
"-i",
1048+
help="Sorted SAM/BAM file containing the aligned reads, if this is not provided (or '-') then 'align_trim' will read from stdin.",
10491049
required=False,
10501050
)
10511051
parser.add_argument(

0 commit comments

Comments
 (0)