telometer 0.74__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.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2024 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: telometer
3
+ Version: 0.74
4
+ Summary: a simple regular expression based method for measuring individual, chromosome-specific telomere lengths from long-read sequencing data
5
+ Author: Santiago E Sanchez
6
+ Author-email: ses94@stanford.edu
7
+ License: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ License-File: LICENSE.txt
13
+
14
+ A simple tool for measuring chromosome-specific telomeres from long-read alignments.
15
+
16
+ [Telometer Github](https://github.com/santiago-es/Telometer)
@@ -0,0 +1,3 @@
1
+ A simple tool for measuring chromosome-specific telomeres from long-read alignments.
2
+
3
+ [Telometer Github](https://github.com/santiago-es/Telometer)
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ import setuptools
2
+
3
+ setuptools.setup(
4
+ name="telometer",
5
+ version="0.74",
6
+ author="Santiago E Sanchez",
7
+ author_email="ses94@stanford.edu",
8
+ description="a simple regular expression based method for measuring individual, chromosome-specific telomere lengths from long-read sequencing data",
9
+ packages=setuptools.find_packages(),
10
+ license='MIT',
11
+ long_description=open('README.md').read(),
12
+ classifiers=[
13
+ "Programming Language :: Python :: 3",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent",
16
+ ],
17
+ python_requires='>=3.7',
18
+ entry_points={
19
+ 'console_scripts': [
20
+ 'telometer=telometer:calculate_telomere_length', # 'telometer' is the command, 'telometer:main' means the main function in telometer.py
21
+ ],
22
+ },
23
+ )
@@ -0,0 +1,2 @@
1
+ from .telometer import calculate_telomere_length
2
+ from .telometer import reverse_complement
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python3
2
+ # Telometer v0.74
3
+ # Created by: Santiago E Sanchez
4
+ # Artandi Lab, Stanford University, 2023
5
+ # Measures telomeres from ONT or PacBio long reads aligned to a T2T genome assembly
6
+ # Simple Usage: telometer -b sorted_t2t.bam -o output.tsv
7
+
8
+ import pysam
9
+ import re
10
+ import regex
11
+ import csv
12
+ import argparse
13
+ import pandas as pd
14
+
15
+ def reverse_complement(seq):
16
+ """Returns the reverse complement of a DNA sequence."""
17
+ complement = {'A': 'T', 'C': 'G', 'G': 'C', 'T': 'A', 'N': 'N'}
18
+ return "".join(complement[base] for base in reversed(seq))
19
+
20
+ def get_adapters(chemistry):
21
+ """Returns the adapter sequences based on the sequencing chemistry."""
22
+ if chemistry == 'r10':
23
+ adapters = ['TTTTTTTTCCTGTACTTCGTTCAGTTACGTATTGCT', 'GCAATACGTAACTGAACGAAGTACAGG']
24
+ else:
25
+ adapters = ['TTTTTTTTTTTAATGTACTTCGTTCAGTTACGTATTGCT', 'GCAATACGTAACTGAACGAAGT']
26
+
27
+ adapters_rc = [reverse_complement(adapter) for adapter in adapters]
28
+ return adapters + adapters_rc
29
+
30
+ def get_telomere_repeats():
31
+ """Returns the telomere repeat sequences."""
32
+ telomere_repeats = ['GGCCA', 'CCCTAA', 'TTAGGG', 'CCCTGG', 'CTTCTT', 'TTAAAA', 'CCTGG']
33
+ telomere_repeats_rc = [reverse_complement(repeat) for repeat in telomere_repeats]
34
+ return telomere_repeats + telomere_repeats_rc
35
+
36
+ def find_initial_boundary_region(sequence, patterns, max_mismatches):
37
+ """Finds the initial boundary region with allowed mismatches."""
38
+ boundary_length = 0
39
+ combined_pattern = '|'.join(f'({pattern})' for pattern in patterns)
40
+ regex_pattern = f'({combined_pattern}){{2,}}'
41
+
42
+ for match in regex.finditer(f'({regex_pattern}){{e<={max_mismatches}}}', sequence, regex.BESTMATCH):
43
+ boundary_length = max(boundary_length, len(match.group(0)))
44
+ return boundary_length
45
+
46
+ def extend_boundary_region(sequence, start, end, patterns, window_size, mismatch_threshold):
47
+ """Extends the boundary region around the initial match, allowing some mismatches."""
48
+ extended_start = max(0, start - window_size)
49
+ extended_end = min(len(sequence), end + window_size)
50
+ extended_seq = sequence[extended_start:extended_end]
51
+
52
+ combined_pattern = ''.join(patterns)
53
+ mismatches = sum(1 for base in extended_seq if base not in combined_pattern)
54
+
55
+ if mismatches / len(extended_seq) <= mismatch_threshold:
56
+ return len(extended_seq) - (end - start) # Additional length
57
+ return 0
58
+
59
+ def calculate_telomere_length():
60
+ # required inputs: bam_file_path, output_file_path, chemistry
61
+ parser = argparse.ArgumentParser(description='Calculate telomere length from a BAM file.')
62
+ parser.add_argument('-b', '--bam', help='The path to the sorted BAM file.', required=True)
63
+ parser.add_argument('-o', '--output', help='The path to the output file.', required=True)
64
+ parser.add_argument('-c', '--chemistry', default="r10", help="Sequencing chemistry (r9 or r10, default=r10). Optional", required=False)
65
+ parser.add_argument('-m', '--minreadlen', default=1000, type=int, help='Minimum read length to consider (Default: 1000 for telomere capture, use 4000 for WGS). Optional', required=False)
66
+ args = parser.parse_args()
67
+ bam_file = pysam.AlignmentFile(args.bam, "rb")
68
+
69
+ adapters = get_adapters(args.chemistry)
70
+ telomere_repeats = get_telomere_repeats()
71
+ telomere_repeats_re = "|".join(f'({repeat}){{2,}}' for repeat in telomere_repeats)
72
+
73
+ highest_mapping_quality = {}
74
+ results = []
75
+ p_count = 0
76
+ q_count = 0
77
+ rev_count = 0
78
+ fwd_count = 0
79
+ p_tel = 0
80
+ q_tel = 0
81
+
82
+ for read in bam_file:
83
+ if read.is_unmapped or read.query_sequence is None or len(read.query_sequence) < args.minreadlen:
84
+ continue
85
+
86
+ alignment_start = read.reference_start
87
+ alignment_end = read.reference_end
88
+ seq = read.query_sequence
89
+
90
+ if read.is_reverse:
91
+ rev_count += 1
92
+ direction = "rev"
93
+ seq = reverse_complement(seq)
94
+ else:
95
+ fwd_count += 1
96
+ direction = "fwd"
97
+
98
+ reference_genome_length = bam_file.get_reference_length(read.reference_name)
99
+
100
+ if alignment_start < 15000 or alignment_start > reference_genome_length - 30000:
101
+ if alignment_start < 15000 and "q" not in read.reference_name:
102
+ arm = "p"
103
+ p_count += 1
104
+ else:
105
+ arm = "q"
106
+ q_count += 1
107
+
108
+ telomere_start = [m.start() for m in re.finditer(telomere_repeats_re, seq)]
109
+ if telomere_start:
110
+ telomere_start = telomere_start[0]
111
+ if telomere_start > 100 and (len(seq) - telomere_start > 200):
112
+ continue
113
+
114
+ telomere_end = min((seq.find(adapter) for adapter in adapters), default=-1)
115
+ if telomere_end == -1:
116
+ telomere_end = len(seq)
117
+
118
+ telomere_region = seq[telomere_start:telomere_end]
119
+ telomere_repeat = [m.group() for m in re.finditer('|'.join(telomere_repeats), telomere_region)]
120
+ telomere_length = len(''.join(telomere_repeat))
121
+
122
+ boundary_mm1_length = find_initial_boundary_region(telomere_region, telomere_repeats, max_mismatches=1)
123
+
124
+ if telomere_length < boundary_mm1_length:
125
+ telomere_length = boundary_mm1_length
126
+ if telomere_length < boundary_mm2_length:
127
+ telomere_length = boundary_mm2_length
128
+
129
+ if read.query_name not in highest_mapping_quality or read.mapping_quality > highest_mapping_quality[read.query_name]:
130
+ if arm == "p":
131
+ p_tel += 1
132
+ else:
133
+ q_tel += 1
134
+ highest_mapping_quality[read.query_name] = read.mapping_quality
135
+ results.append({
136
+ 'chromosome': read.reference_name,
137
+ 'reference_start': alignment_start,
138
+ 'reference_end': alignment_end,
139
+ 'telomere_length': telomere_length,
140
+ 'subtel_boundary_length': boundary_mm1_length,
141
+ 'read_id': read.query_name,
142
+ 'mapping_quality': read.mapping_quality,
143
+ 'read_length': len(seq),
144
+ 'arm': arm,
145
+ 'direction': direction
146
+ })
147
+
148
+ bam_file.close()
149
+
150
+ with open(args.output, 'w', newline='') as output_file:
151
+ writer = csv.DictWriter(output_file, fieldnames=results[0].keys(), delimiter='\t')
152
+ writer.writeheader()
153
+ writer.writerows(results)
154
+
155
+ # Print the total number of telomeres measured
156
+ print(f"Telometer completed successfully. Total telomeres measured: {len(results)}")
157
+
158
+ if __name__ == "__main__":
159
+ calculate_telomere_length()
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: telometer
3
+ Version: 0.74
4
+ Summary: a simple regular expression based method for measuring individual, chromosome-specific telomere lengths from long-read sequencing data
5
+ Author: Santiago E Sanchez
6
+ Author-email: ses94@stanford.edu
7
+ License: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ License-File: LICENSE.txt
13
+
14
+ A simple tool for measuring chromosome-specific telomeres from long-read alignments.
15
+
16
+ [Telometer Github](https://github.com/santiago-es/Telometer)
@@ -0,0 +1,10 @@
1
+ LICENSE.txt
2
+ README.md
3
+ setup.py
4
+ telometer/__init__.py
5
+ telometer/telometer.py
6
+ telometer.egg-info/PKG-INFO
7
+ telometer.egg-info/SOURCES.txt
8
+ telometer.egg-info/dependency_links.txt
9
+ telometer.egg-info/entry_points.txt
10
+ telometer.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ telometer = telometer:calculate_telomere_length
@@ -0,0 +1 @@
1
+ telometer