annotate cpt_convert_xmfa/xmfa.py @ 0:06d8e28d0bd7 draft default tip

Uploaded
author cpt
date Fri, 10 Jun 2022 08:49:43 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
1 # This file is licensed seperately of the rest of the codebase. This is due to
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
2 # BioPython's failure to merge https://github.com/biopython/biopython/pull/544
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
3 # in a timely fashion. Please use this file however you see fit!
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
4 #
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
5 #
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
6 # Copyright (c) 2015-2017 Center for Phage Technology. All rights reserved.
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
7 # Redistribution and use in source and binary forms, with or without
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
8 # modification, are permitted provided that the following conditions are met:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
9 #
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
10 # 1. Redistributions of source code must retain the above copyright notice, this
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
11 # list of conditions and the following disclaimer.
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
12 #
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
13 # 2. Redistributions in binary form must reproduce the above copyright notice,
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
14 # this list of conditions and the following disclaimer in the documentation
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
15 # and/or other materials provided with the distribution.
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
16 #
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
17 # THIS SOFTWARE IS PROVIDED BY CENTER FOR PHAGE TECHNOLOGY "AS IS" AND ANY
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
20 # DISCLAIMED. IN NO EVENT SHALL CENTER FOR PHAGE TECHNOLOGY OR CONTRIBUTORS BE
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
21 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
22 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
23 # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
24 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
26 # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
27 from Bio import SeqIO
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
28 import tempfile
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
29 import sys
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
30
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
31
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
32 def parse_xmfa(xmfa):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
33 """Simple XMFA parser until https://github.com/biopython/biopython/pull/544
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
34 """
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
35 current_lcb = []
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
36 current_seq = {}
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
37 for line in xmfa.readlines():
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
38 if line.startswith("#"):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
39 continue
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
40
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
41 if line.strip() == "=":
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
42 if "id" in current_seq:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
43 current_lcb.append(current_seq)
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
44 current_seq = {}
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
45 yield current_lcb
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
46 current_lcb = []
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
47 else:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
48 line = line.strip()
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
49 if line.startswith(">"):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
50 if "id" in current_seq:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
51 current_lcb.append(current_seq)
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
52 current_seq = {}
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
53 data = line.strip().split()
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
54 # 0 1 2 3 4 5
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
55 # > 1:5986-6406 + CbK.fa # CbK_gp011
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
56 id, loc = data[1].split(":")
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
57 start, end = loc.split("-")
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
58 current_seq = {
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
59 "rid": "_".join(data[1:]),
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
60 "id": id,
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
61 "start": int(start),
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
62 "end": int(end),
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
63 "strand": 1 if data[2] == "+" else -1,
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
64 "file": data[3],
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
65 "seq": "",
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
66 "comment": "",
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
67 }
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
68 if len(data) > 5:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
69 current_seq["comment"] = " ".join(data[5:])
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
70 else:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
71 current_seq["seq"] += line.strip()
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
72
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
73
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
74 HEADER_TPL = "> {id}:{start}-{end} {strand} {file} # {comment}\n"
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
75
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
76
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
77 def split_by_n(seq, n):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
78 """A generator to divide a sequence into chunks of n units."""
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
79 # http://stackoverflow.com/questions/9475241/split-python-string-every-nth-character
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
80 while seq:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
81 yield seq[:n]
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
82 seq = seq[n:]
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
83
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
84
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
85 def to_xmfa(lcbs, handle=sys.stdout):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
86 handle.write("#FormatVersion Mauve1\n")
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
87 for lcb in lcbs:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
88 for aln in lcb:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
89 handle.write(
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
90 HEADER_TPL.format(
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
91 id=aln["id"],
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
92 start=aln["start"],
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
93 end=aln["end"],
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
94 strand="+" if aln["strand"] > 0 else "-",
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
95 file=aln["file"],
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
96 comment=aln["comment"],
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
97 )
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
98 )
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
99
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
100 for line in split_by_n(aln["seq"], 80):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
101 handle.write(line + "\n")
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
102 handle.write("=\n")
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
103
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
104
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
105 def percent_identity(a, b):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
106 """Calculate % identity, ignoring gaps in the host sequence
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
107 """
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
108 match = 0
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
109 mismatch = 0
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
110 for char_a, char_b in zip(list(a), list(b)):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
111 if char_a == "-":
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
112 continue
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
113 if char_a == char_b:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
114 match += 1
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
115 else:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
116 mismatch += 1
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
117
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
118 if match + mismatch == 0:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
119 return 0.0
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
120 return 100 * float(match) / (match + mismatch)
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
121
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
122
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
123 def id_tn_dict(sequences, tmpfile=False):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
124 """Figure out sequence IDs
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
125 """
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
126 label_convert = {}
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
127 correct_chrom = None
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
128 if not isinstance(sequences, list):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
129 sequences = [sequences]
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
130
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
131 i = 0
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
132 for sequence_file in sequences:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
133 for record in SeqIO.parse(sequence_file, "fasta"):
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
134 if correct_chrom is None:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
135 correct_chrom = record.id
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
136
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
137 i += 1
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
138 key = str(i)
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
139 label_convert[key] = {"record_id": record.id, "len": len(record.seq)}
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
140
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
141 if tmpfile:
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
142 label_convert[key] = tempfile.NamedTemporaryFile(delete=False)
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
143
06d8e28d0bd7 Uploaded
cpt
parents:
diff changeset
144 return label_convert