-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomputeInterface.py
More file actions
204 lines (170 loc) · 10.5 KB
/
computeInterface.py
File metadata and controls
204 lines (170 loc) · 10.5 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
#!/usr/bin/env python
# -*- coding : utf8 -*-
"""
Authors: Maud De Tollenaere & Severine Liegeois
Contact: de.tollenaere.maud@gmail.com & sliegeois@yahoo.fr
Date: 02/05/2017
Description: Script containing functions for computing distances and time of contacts
between residues of proteins.
"""
from RMSD import *
import numpy as np
import matplotlib.pyplot as plt
import math
def distDico(res1, res2, mode):
"""
Calcule la distance entre 2 residus.
:param res1: Dictionnaire correspondant au premier residu.
:param res2: Dictionnaire correspondant au second residu.
:param mode: Mode de calcul de la distance (distance entre les 2 atomes les plus proches, ou entre les centres de masse).
:return: La distance entre les 2 residus.
"""
if mode == "CM": # distance entre les centres de masse des residus
CM_res1 = centerOfMass(res1)
CM_res2 = centerOfMass(res2)
minval = math.sqrt(distanceCarree(CM_res1, CM_res2))
elif mode == "atom": # distance entre les atomes les plus proches des 2 residus
minval = 1000000
for atom1 in res1['atomlist']:
for atom2 in res2['atomlist']:
dist = math.sqrt(distanceCarree(res1[atom1], res2[atom2]))
if dist < minval:
minval = dist
return minval
def distMatrix(dico, dom1, dom2, mode):
"""
Calcule la matrice des distances entre 2 domaines proteiques ou entre 1 domaine et l'ARN.
:param dico: Dictionnaire correspondant au complexe proteine-ARN.
:param dom1: Nom du premier domaine a utiliser.
:param dom2: Nom du second domaine a utiliser.
:param mode: Mode de calcul de la distance entre les domaines: par rapport au centre de masse ('CM') ou entre les 2 atomes les plus proches ('atom').
"""
list1 = dico[dom1]['reslist'] # liste des residus du premier domaine
list2 = dico[dom2]['reslist'] # liste des residus du second domaine
nb_row = len(list1) # nombre de lignes de la matrice = nombre de residus dans le premier domaine
nb_col = len(list2) # nombre de colonnes de la matrice = nombre de residus dans le second domaine
distmat = []
dic1 = dico[dom1] # pour simplifier l'ecriture par la suite
dic2 = dico[dom2]
for i in range(nb_row): # pour chaque residu i du premier domaine ...
listi = [] # chaque ligne de la matrice est une liste
for j in range(nb_col):
dij = distDico(dic1[list1[i]], dic2[list2[j]],
mode) # ... on calcule sa distance avec le j-eme residu du second domaine
listi.append(dij) # et on ajoute cette distance a la liste representant la i-eme ligne de la matrice
distmat.append(listi) # la ligne est ajoutee a la matrice : distmat est une liste de liste
# Representer la matrice sous forme de heatmap
data = np.array(distmat).reshape(nb_row, nb_col) # la matrice est transformee en array
plt.pcolor(data, cmap="RdBu_r") # choix du systeme de coloration
plt.xticks(np.arange(nb_col) + 0.5, list2, fontsize=5) # positionnement des etiquettes sur l'abscisse
plt.yticks(np.arange(nb_row) + 0.5, list1, fontsize=5) # idem sur l'ordonnee
plt.xlabel(dom2) # le domaine 2 est represente par les colonnes (abscisse) de la matrice
plt.ylabel(dom1)
cb = plt.colorbar() # ajout d'une echelle des couleurs
cb.set_label('Distance between residues of %s and %s\nin Angstrom'%(dom1,dom2)) # titre de la legende
plt.show()
# ------------------------------------------------------------------------------------------
def resInterface(dico, prot_domains, rna_dom, threshold, mode, output, **writing_param):
"""
Calcule les frequences d'appartenance a l'interface proteine/ARN pour chacun des residus de la proteine, et les retourne dans un fichier texte de sortie.
:param dico: Dictionnaire representant le complexe proteine/ARN.
:param prot_domains: Liste contenant les noms des domaines proteiques a considerer.
:param rna_dom: Nom du domaine correspondant a l'ARN.
:param threshold: Seuil en Angstrom, correspond a la distance ARN-residu en-dessous de laquelle le residu appartient a l'interface.
:param mode: Mode de calcul de la distance entre les domaines.
:param output: Fichier texte contenant les frequences non nulles d'appartenance a l'interface des residus.
:param writing_param: Parametre optionnel: si present, le dictionnaire d'entree est modifie en ajoutant pour chaque residu le B-factor (0.00 si le residu n'appartient pas a l'interface, 1.00 sinon).
:return: Dictionnaire correspondant aux residus dont la frequence d'appartenance a l'interface est non nulle.
"""
inInterface = dict()
for dom in prot_domains: # pour chaque domaine proteique ...
inInterface[dom] = dict() # ... on cree un dictionnaire de dictionnaire
inInterface[dom]['reslist'] = [] # contiendra la liste des residus du domaine
for model in dico.keys():
for res1 in dico[model][dom]['reslist']: # pour chaque residu
if res1 not in inInterface[dom]['reslist']: # si le residu n'a pas encore ete traite pour ce domaine
inInterface[dom][res1] = 0 # on initialise a 0 le nombre de fois qu'il se trouve dans l'interface
inInterface[dom]['reslist'].append(res1) # on ajoute le residu dans la liste
min = 60 # initialisation de la distance minimale residu-ARN
for res2 in dico[model][rna_dom]['reslist']:
d = distDico(dico[model][dom][res1], dico[model][rna_dom][res2],
mode) # on calcule la distance entre le residu et tous les nucleotides de l'ARN
dico[model][rna_dom][res2]['bfactor'] = 0.00
if d < min: # si la distance entre le residu et le nucleotide est plus petite que la valeur minimale
min = d # min sera donc la distance entre le residu et le nucleotide le plus proche
if min <= threshold:
inInterface[dom][res1] = inInterface[dom][res1] + 1
dico[model][dom][res1]['bfactor'] = 1.00
else:
dico[model][dom][res1]['bfactor'] = 0.00
# Optionnel: remet le dictionnaire modifie au format pdb, pour une visualisation dans PyMol
if 'writePDB' in writing_param:
writePDBframes(dico, writing_param['writePDB'], prot_domains, rna_dom)
# Retourne les frequences (si non nulles) dans un fichier texte:
f = open(output, "w")
res_interface = dict()
for dom in inInterface.keys():
res_interface[dom] = dict()
f.write("Domain " + dom + "\n\tResidue\tFrequence\n")
for res in inInterface[dom]['reslist']:
freq = inInterface[dom][res] / len(dico.keys())
if freq != 0:
f.write("\t" + res + "\t" + str(freq) + "\n")
res_interface[dom][res] = freq
f.close()
return res_interface
def writePDBframes(dico, output, list_dom_prot, rna_dom):
"""
Utilise un dictionnaire contenant plusieurs conformations pour ecrire un fichier pdb visualisable sous PyMol.
:param dico: Dictionnaire contenant les differentes conformations.
:param output: Nom du fichier de sortie.
:param list_dom_prot: Liste des domaines proteiques.
:param rna_dom: Domaine correspondant a l'ARN.
:return: Un fichier pdb au format ATOM.
"""
fout = open(output, "w")
for model in dico.keys():
fout.write("MODEL\t" + str(model) + "\n")
for dom in list_dom_prot:
for res in dico[model][dom]['reslist']:
for atom in dico[model][dom][res]['atomlist']:
fout.write(
"{:6s}{:5s} {:4s}{:1s}{:3s} {:1s}{:4s}{:1s} {:8.3f}{:8.3f}{:8.3f}{:6.2f}{:6.2f} {:^4s}\n".format(
"ATOM", dico[model][dom][res][atom]['id'], atom, '', dico[model][dom][res]['resname'],
'', res, '', dico[model][dom][res][atom]['x'], dico[model][dom][res][atom]['y'],
dico[model][dom][res][atom]['z'],
1.00, dico[model][dom][res]['bfactor'], dom))
for dom2 in rna_dom:
for nucl in dico[model][dom2]['reslist']:
for atom in dico[model][dom2][nucl]['atomlist']:
fout.write(
"{:6s}{:5s} {:4s}{:1s}{:3s} {:1s}{:4s}{:1s} {:8.3f}{:8.3f}{:8.3f}{:6.2f}{:6.2f} {:^4s}\n".format(
"ATOM", dico[model][dom2][nucl][atom]['id'], atom, '', dico[model][dom2][nucl]['resname'],
'', nucl, '', dico[model][dom2][nucl][atom]['x'], dico[model][dom2][nucl][atom]['y'],
dico[model][dom2][nucl][atom]['z'],
1.00, 0.00, dom2))
fout.write("ENDMDL\n")
fout.close()
# -------------------------------------------------------------------------
def contactTime(pairs, frames_dico, threshold, duration, mode, output):
"""
Calcule le temps de contact entre differentes paires de residus.
:param pairs: Dictionnaire contenant les paires de residus.
:param frames_dico: Dictionnaire contenant toutes les conformations.
:param threshold: Seuil (en Angstrom) pour definir le contact.
:param duration: Duree de la dynamique.
:param mode: Mode de calcul des distances.
:param output: Nom du fichier de sortie.
:return: Fichier texte contenant les temps de contact entre paires de residus.
"""
f=open(output, "w")
for res in pairs.keys():
pairs[res]['contact time'] = 0 # nombre de conformations pour lesquelles les residus sont en contact
for model in frames_dico.keys():
d = distDico(frames_dico[model][pairs[res]['dom1']][res], frames_dico[model][pairs[res]['dom2']][pairs[res]['res2']], mode)
if d <= threshold:
pairs[res]['contact time'] += 1
pairs[res]['contact time'] = pairs[res]['contact time']*duration/len(frames_dico.keys()) # duree de contact
f.write("Residue " + res + "(domain " + pairs[res]['dom1'] + ") - " + "Residue " + pairs[res]['res2'] + "(domain " + pairs[res]['dom2'] + ") : " +
str(pairs[res]['contact time']) + " ns\n")
f.close()