This repository was archived by the owner on Jul 16, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwholetreetriplealignmentset.py
More file actions
273 lines (201 loc) · 14 KB
/
Copy pathwholetreetriplealignmentset.py
File metadata and controls
273 lines (201 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
####################################################################################################
# #
# PROJECT Protein Adaptation #
# CLASS WholeTreeTripleAlignmentSet #
# PROGRAMMER Jeremy Adams #
# STARTED 08-01-14 #
# LASTMOD 06-11-14 #
# #
# DESCRIPTION Class that aligns the representative sequence to PDB structures, and #
# instantiates mutation cataloguing and analysis for each branch segment #
# #
####################################################################################################
import re
from fasequence import FASequence
from adalignment import ADAlignment
from referencetopdb2dscoringmatrix import ReferenceToPDB2DScoringMatrix
from triplealignment import TripleAlignment
from staticmethods import *
class WholeTreeTripleAlignmentSet:
"""
Class attributes:
RepresentativeSeqWithGaps (FASequence Obj): Sequence containing information on the most representative extant sequence of the entire set
TreeNodeToReconstructedSeq_D (Dict): Key is the tree node name, value is the sequence at that node
BranchKey_L (List): list of all branch segments denoted by ancestral and derived branch keys
Probability_D (Dict): dictionary of reconstruction probabilities for all nodes
RepresentativeSeqWithoutGaps (FASequence Obj): Same sequence as the with gap sequence although with gaps removed
RepresentativeSeqScoringMatrix (Reference2PDBScoringMatrix Obj): 2-D grid object of the RepresentativeSeqWithGaps object
PDBFile_L (list): list of PDB ID accessions used for this protein family
TripleAlignments_D (Dict): Key is the branch key, value is a TripleAlignment object representing that branch
ExitString (String): Report XML for all branches
MatrixGraphicsXML (String): Scoring keys for PDB alignment boundaries
"""
"CONSTRUCTOR"
def __init__(self , RepresentativeSeqWithGaps , TreeNodeToReconstructedSeq_D , BranchKey_L , Probability_D):
#variables from WholeTreeOrthologousSubgroup
self.RepresentativeSeqWithGaps = RepresentativeSeqWithGaps
self.TreeNodeToReconstructedSeq_D = TreeNodeToReconstructedSeq_D
self.BranchKey_L = BranchKey_L
self.Probability_D = Probability_D
#gets gaps from the with gap seq and prepares the sequence without gaps
GapIndicesAndWithoutGapSeq_D = self.getListOfGapIndices()
self.RepresentativeSeqWithoutGaps = GapIndicesAndWithoutGapSeq_D["WithoutGapSeq"]
self.GapIndices = GapIndicesAndWithoutGapSeq_D["GapIndices"]
#BLASTs the sequence without gaps to the PDB
self.RepresentativeSeqWithoutGaps.completeMasterList()
#adds gaps to the with gap PDBMasterList and gets the scoring matrix for it
self.RepresentativeSeqWithGaps.PDBMasterList = self.gapCorrectPDBMasterList(self.RepresentativeSeqWithoutGaps.PDBMasterList , self.GapIndices , len(self.RepresentativeSeqWithGaps.info['sequence']))
self.RepresentativeSeqScoringMatrix = ReferenceToPDB2DScoringMatrix(self.RepresentativeSeqWithGaps.referenceSequencePrint())
self.PDBFile_L = self.getPDBFile_L()
#performs TripleAlignments for each branch in the overall tree
self.TripleAlignments_D = {}
for branchKey in self.BranchKey_L:
branchSplit = branchKey.split(">>")
if branchSplit[0] in self.TreeNodeToReconstructedSeq_D.keys() and branchSplit[1] in self.TreeNodeToReconstructedSeq_D.keys():
adAlignment = ADAlignment(self.TreeNodeToReconstructedSeq_D[branchSplit[0]] , self.TreeNodeToReconstructedSeq_D[branchSplit[1]] , Probability_D[branchSplit[0]] , Probability_D[branchSplit[1]])
self.TripleAlignments_D[branchKey] = TripleAlignment(adAlignment.mutations,\
self.RepresentativeSeqScoringMatrix,\
self.PDBFile_L,\
"\t\t\t\t\t\t\t")
#prepares report XML and scoring matrix XML
self.ExitString = self.getExitString()
self.MatrixGraphicsXML = self.RepresentativeSeqScoringMatrix.scoringMatrixXMLPrint()
"gets list of gaps and gap lengths in the sequence to prepare for reinsertion"
def getListOfGapIndices(self):
seq_with_gaps = self.RepresentativeSeqWithGaps.info['sequence']
missing_gaps_in_the_without_gap_seq = []
without_gap_seq = []
a_gap_has_been_found = False
the_gap_has_ended = False
gap_start = 0
#for each state in the sequence
for i in range(0,len(seq_with_gaps)):
#if in gap mode
if a_gap_has_been_found:
if seq_with_gaps[i] != "-": #ends the gap when the "-" is not found
gap_end = i
missing_gaps_in_the_without_gap_seq.append([gap_start , gap_end , len(without_gap_seq)])
without_gap_seq.append(seq_with_gaps[i])
a_gap_has_been_found = False
elif i == len(seq_with_gaps) - 1:
missing_gaps_in_the_without_gap_seq.append([gap_start , len(seq_with_gaps) , len(without_gap_seq)])
#if not in gap mode and looking for a gap
else:
if seq_with_gaps[i] == "-": #starts the gap when the "-" is found
gap_start = i
a_gap_has_been_found = True
else:
without_gap_seq.append(seq_with_gaps[i])
return {'WithoutGapSeq' : FASequence('seq_without_gaps' , ''.join(without_gap_seq)),\
'GapIndices' : missing_gaps_in_the_without_gap_seq}
"reinsert gaps and adjust alignment coordinates appropriately in the PDB sequence"
def gapCorrectPDBMasterList(self , pdb_master_list , gap_indices , query_length):
corrected_list = []
#for each target sequence in the master list
for pdb_hit in pdb_master_list:
new_qseq = []
new_sseq = []
old_seq_index_counter = 0
#gets old information from BLASTing with the without gap seq
old_qseq = get_qseq(pdb_hit)
old_sseq = get_sseq(pdb_hit)
old_qstart = int(get_qstart(pdb_hit))
old_seq_blast_numbering_index_counter = old_qstart
old_qend = int(get_qend(pdb_hit))
#for each gap found in the with gap seq
#adds gaps to the sseq (PDB) and qseq (representative sequence without gaps) wherever there were gap indices
for gap in gap_indices:
gap_position_in_the_without_gap_seq = gap[2] + 1
if gap_position_in_the_without_gap_seq >= old_qstart and gap_position_in_the_without_gap_seq <= old_qend:
blast_alignment_seq_before_gaps = old_qseq[old_seq_index_counter:old_seq_index_counter+(gap_position_in_the_without_gap_seq-old_seq_blast_numbering_index_counter)]
gaps_in_the_blast_alignment = blast_alignment_seq_before_gaps.count("-")
if gaps_in_the_blast_alignment == 0:
pass
else:
blast_alignment_seq_is_not_satisfied = True
while blast_alignment_seq_is_not_satisfied:
blast_alignment_candidate = old_qseq[old_seq_index_counter:old_seq_index_counter+(gap_position_in_the_without_gap_seq-old_seq_blast_numbering_index_counter)+gaps_in_the_blast_alignment]
new_amount_of_gaps_in_the_blast_alignment = blast_alignment_candidate.count("-")
if new_amount_of_gaps_in_the_blast_alignment == gaps_in_the_blast_alignment:
blast_alignment_seq_is_not_satisfied = False
blast_alignment_seq_before_gaps = blast_alignment_candidate
else:
gaps_in_the_blast_alignment = new_amount_of_gaps_in_the_blast_alignment
new_qseq.append(blast_alignment_seq_before_gaps)
new_sseq.append(old_sseq[old_seq_index_counter:old_seq_index_counter+(gap_position_in_the_without_gap_seq-old_seq_blast_numbering_index_counter)+gaps_in_the_blast_alignment])
new_qseq.append("-" * (gap[1] - gap[0]))
new_sseq.append("-" * (gap[1] - gap[0]))
new_qseq.append(old_qseq[old_seq_index_counter+(gap_position_in_the_without_gap_seq-old_seq_blast_numbering_index_counter)])
new_sseq.append(old_sseq[old_seq_index_counter+(gap_position_in_the_without_gap_seq-old_seq_blast_numbering_index_counter)])
old_seq_index_counter = old_seq_index_counter+(gap_position_in_the_without_gap_seq-old_seq_blast_numbering_index_counter)+gaps_in_the_blast_alignment+1
old_seq_blast_numbering_index_counter = gap_position_in_the_without_gap_seq+1
new_qseq.append(old_qseq[old_seq_index_counter:])
new_sseq.append(old_sseq[old_seq_index_counter:])
#places the new sequence lists into a single string
new_qseq = ''.join(new_qseq)
new_sseq = ''.join(new_sseq)
#finds different start and end coordinates for the with gap seq alignments by adjusting the original without gap seq start and end coordinates
new_qstart_not_found = True
new_qend_not_found = True
new_qstart = 0
new_qend = 0
new_sstart = 0
new_send = 0
if len(gap_indices) > 0 :
for i in range(0,len(gap_indices)):
if new_qstart_not_found:
if (gap_indices[i][2] + 1) >= old_qstart:
for a in range(0,i):
new_qstart += (gap_indices[a][1] - gap_indices[a][0])
new_qstart += old_qstart
new_qstart_not_found = False
else:
if new_qend_not_found:
if (gap_indices[i][2] + 1) >= old_qend:
for a in range(0,i):
new_qend += (gap_indices[a][1] - gap_indices[a][0])
new_qend += old_qend
new_qend_not_found = False
else:
new_qstart = old_qstart
new_qend = old_qend
#creates a similar line as in the without gap seq, but with the correctly adjusted gaps
list_item = []
list_item.append(get_qcovs(pdb_hit))
list_item.append(get_evalue(pdb_hit))
list_item.append(get_bitscore(pdb_hit))
list_item.append(get_sseqid(pdb_hit))
list_item.append(str(query_length))
list_item.append(str(new_qstart))
list_item.append(str(new_qend))
list_item.append(new_qseq)
list_item.append(get_slen(pdb_hit))
list_item.append(get_sstart(pdb_hit))
list_item.append(get_send(pdb_hit))
list_item.append(new_sseq)
list_item.append(get_qcovhsp(pdb_hit))
corrected_list.append(','.join(list_item))
return corrected_list
"gets a list of PDB ID accessions from the overall sequence alignment"
def getPDBFile_L(self):
ret = []
#reads the processed XML of the scoring matrix and finds all unique PDB IDs
if self.RepresentativeSeqScoringMatrix.ProcessedXML:
for pdb in self.RepresentativeSeqScoringMatrix.ProcessedXML['pdb_files']:
accession = pdb['pdb_id'].split("|")[0].lower()
this_file_has_not_yet_been_read = True
for key in ret:
if key == accession:
this_file_has_not_yet_been_read = False
if this_file_has_not_yet_been_read:
ret.append(accession)
return ret
"gets the main report XML string using all of the TripleAlignment reports"
def getExitString(self):
#adds the Branch tag to each TripleAlignment report string
Ret = ["\t\t\t\t<Branches>\n"]
for branchKey in self.BranchKey_L:
Ret = Ret + ["\t\t\t\t\t<Branch>\n" , "\t\t\t\t\t\t<Branch_name>%s</Branch_name>\n" % (branchKey) , "\t\t\t\t\t\t<Muts>\n" ,\
self.TripleAlignments_D[branchKey].exit['exit_string'] , "\t\t\t\t\t\t</Muts>\n" , "\t\t\t\t\t</Branch>\n"]
Ret.append("\t\t\t\t</Branches>\n")
return "".join(Ret)