Fast-HInt-ppi 0.1.2__tar.gz → 0.1.3__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.
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/__init__.py +1 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/calculate_mpdockq.py +190 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/clean_pdb.py +62 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/interface_assess.py +154 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/pi_score_utils.py +279 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/pisa_utils.py +64 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/run_piscore_wc.py +214 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/sc_utils.py +81 -0
- fast_hint_ppi-0.1.3/Fast_HInt/script_pi_score/svm_model/__init__.py +1 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt_ppi.egg-info/PKG-INFO +1 -1
- fast_hint_ppi-0.1.3/Fast_HInt_ppi.egg-info/SOURCES.txt +23 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/PKG-INFO +1 -1
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/setup.py +1 -1
- fast_hint_ppi-0.1.2/Fast_HInt_ppi.egg-info/SOURCES.txt +0 -14
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt/Fast_HInt.py +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt/File_proteins.py +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt/Scoring_HInt.py +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt/Utils_HInt.py +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt/__init__.py +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt/get_good_inter_pae.py +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt_ppi.egg-info/dependency_links.txt +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt_ppi.egg-info/entry_points.txt +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt_ppi.egg-info/requires.txt +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/Fast_HInt_ppi.egg-info/top_level.txt +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/README.md +0 -0
- {fast_hint_ppi-0.1.2 → fast_hint_ppi-0.1.3}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""script_pi_score"""
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#Adapted from calculate_mpdockq.py (https://github.com/KosinskiLab/AlphaPulldown/blob/main/alphapulldown/analysis_pipeline/alpha_analysis_jax0.4.def)
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
import math
|
|
6
|
+
|
|
7
|
+
################FUNCTIONS#################
|
|
8
|
+
def parse_atm_record(line):
|
|
9
|
+
'''Get the atm record
|
|
10
|
+
'''
|
|
11
|
+
record = defaultdict()
|
|
12
|
+
record['name'] = line[0:6].strip()
|
|
13
|
+
record['atm_no'] = int(line[6:11].strip())
|
|
14
|
+
record['atm_name'] = line[12:16].strip()
|
|
15
|
+
record['atm_alt'] = line[17]
|
|
16
|
+
record['res_name'] = line[17:20].strip()
|
|
17
|
+
record['chain'] = line[21]
|
|
18
|
+
record['res_no'] = int(line[22:26].strip())
|
|
19
|
+
record['insert'] = line[26].strip()
|
|
20
|
+
record['resid'] = line[22:29]
|
|
21
|
+
record['x'] = float(line[30:38])
|
|
22
|
+
record['y'] = float(line[38:46])
|
|
23
|
+
record['z'] = float(line[46:54])
|
|
24
|
+
record['occ'] = float(line[54:60])
|
|
25
|
+
record['B'] = float(line[60:66])
|
|
26
|
+
|
|
27
|
+
return record
|
|
28
|
+
|
|
29
|
+
def read_pdb(pdbfile):
|
|
30
|
+
'''Read a pdb file per chain
|
|
31
|
+
'''
|
|
32
|
+
pdb_chains = {}
|
|
33
|
+
chain_coords = {}
|
|
34
|
+
chain_CA_inds = {}
|
|
35
|
+
chain_CB_inds = {}
|
|
36
|
+
|
|
37
|
+
with open(pdbfile) as file:
|
|
38
|
+
for line in file:
|
|
39
|
+
if 'ATOM' in line:
|
|
40
|
+
record = parse_atm_record(line)
|
|
41
|
+
if record['chain'] in [*pdb_chains.keys()]:
|
|
42
|
+
pdb_chains[record['chain']].append(line)
|
|
43
|
+
chain_coords[record['chain']].append([record['x'],record['y'],record['z']])
|
|
44
|
+
coord_ind+=1
|
|
45
|
+
if record['atm_name']=='CA':
|
|
46
|
+
chain_CA_inds[record['chain']].append(coord_ind)
|
|
47
|
+
if record['atm_name']=='CB' or (record['atm_name']=='CA' and record['res_name']=='GLY'):
|
|
48
|
+
chain_CB_inds[record['chain']].append(coord_ind)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
else:
|
|
52
|
+
pdb_chains[record['chain']] = [line]
|
|
53
|
+
chain_coords[record['chain']]= [[record['x'],record['y'],record['z']]]
|
|
54
|
+
chain_CA_inds[record['chain']]= []
|
|
55
|
+
chain_CB_inds[record['chain']]= []
|
|
56
|
+
#Reset coord ind
|
|
57
|
+
coord_ind = 0
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
return pdb_chains, chain_coords, chain_CA_inds, chain_CB_inds
|
|
61
|
+
|
|
62
|
+
def read_plddt(best_plddt, chain_CA_inds):
|
|
63
|
+
'''Get the plDDT for each chain
|
|
64
|
+
'''
|
|
65
|
+
chain_names = chain_CA_inds.keys()
|
|
66
|
+
chain_lengths = dict()
|
|
67
|
+
for name in chain_names:
|
|
68
|
+
curr_len = len(chain_CA_inds[name])
|
|
69
|
+
chain_lengths[name] = curr_len
|
|
70
|
+
|
|
71
|
+
plddt_per_chain = dict()
|
|
72
|
+
curr_len = 0
|
|
73
|
+
for k,v in chain_lengths.items():
|
|
74
|
+
curr_plddt = best_plddt[curr_len:curr_len+v]
|
|
75
|
+
plddt_per_chain[k] = curr_plddt
|
|
76
|
+
curr_len += v
|
|
77
|
+
return plddt_per_chain
|
|
78
|
+
|
|
79
|
+
def score_complex(path_coords, path_CB_inds, path_plddt):
|
|
80
|
+
'''
|
|
81
|
+
Score all interfaces in the current complex
|
|
82
|
+
|
|
83
|
+
Modified from the score_complex() function in MoLPC repo:
|
|
84
|
+
https://gitlab.com/patrickbryant1/molpc/-/blob/main/src/complex_assembly/score_entire_complex.py#L106-154
|
|
85
|
+
'''
|
|
86
|
+
|
|
87
|
+
chains = [*path_coords.keys()]
|
|
88
|
+
chain_inds = np.arange(len(chains))
|
|
89
|
+
complex_score = 0
|
|
90
|
+
#Get interfaces per chain
|
|
91
|
+
for i in chain_inds:
|
|
92
|
+
chain_i = chains[i]
|
|
93
|
+
chain_coords = np.array(path_coords[chain_i])
|
|
94
|
+
chain_CB_inds = path_CB_inds[chain_i]
|
|
95
|
+
l1 = len(chain_CB_inds)
|
|
96
|
+
chain_CB_coords = chain_coords[chain_CB_inds]
|
|
97
|
+
chain_plddt = path_plddt[chain_i]
|
|
98
|
+
|
|
99
|
+
for int_i in np.setdiff1d(chain_inds, i):
|
|
100
|
+
int_chain = chains[int_i]
|
|
101
|
+
int_chain_CB_coords = np.array(path_coords[int_chain])[path_CB_inds[int_chain]]
|
|
102
|
+
int_chain_plddt = path_plddt[int_chain]
|
|
103
|
+
#Calc 2-norm
|
|
104
|
+
mat = np.append(chain_CB_coords,int_chain_CB_coords,axis=0)
|
|
105
|
+
a_min_b = mat[:,np.newaxis,:] -mat[np.newaxis,:,:]
|
|
106
|
+
dists = np.sqrt(np.sum(a_min_b.T ** 2, axis=0)).T
|
|
107
|
+
contact_dists = dists[:l1,l1:]
|
|
108
|
+
contacts = np.argwhere(contact_dists<=8)
|
|
109
|
+
#The first axis contains the contacts from chain 1
|
|
110
|
+
#The second the contacts from chain 2
|
|
111
|
+
if contacts.shape[0]>0:
|
|
112
|
+
av_if_plDDT = np.concatenate((chain_plddt[contacts[:,0]], int_chain_plddt[contacts[:,1]])).mean()
|
|
113
|
+
complex_score += np.log10(contacts.shape[0]+1)*av_if_plDDT
|
|
114
|
+
|
|
115
|
+
return complex_score, len(chains)
|
|
116
|
+
|
|
117
|
+
def calculate_mpDockQ(complex_score):
|
|
118
|
+
"""
|
|
119
|
+
A function that returns a complex's mpDockQ score after
|
|
120
|
+
calculating complex_score
|
|
121
|
+
"""
|
|
122
|
+
L = 0.827
|
|
123
|
+
x_0 = 261.398
|
|
124
|
+
k = 0.036
|
|
125
|
+
b = 0.221
|
|
126
|
+
return L/(1+math.exp(-1*k*(complex_score-x_0))) + b
|
|
127
|
+
|
|
128
|
+
def read_pdb_pdockq(pdbfile):
|
|
129
|
+
'''Read a pdb file predicted with AF and rewritten to conatin all chains
|
|
130
|
+
Adepted from FoldDock repo:
|
|
131
|
+
https://gitlab.com/ElofssonLab/FoldDock/-/blob/main/src/pdockq.py#L34-59
|
|
132
|
+
'''
|
|
133
|
+
|
|
134
|
+
chain_coords, chain_plddt = {}, {}
|
|
135
|
+
with open(pdbfile, 'r') as file:
|
|
136
|
+
for line in file:
|
|
137
|
+
if not line.startswith('ATOM'):
|
|
138
|
+
continue
|
|
139
|
+
record = parse_atm_record(line)
|
|
140
|
+
#Get CB - CA for GLY
|
|
141
|
+
if record['atm_name']=='CB' or (record['atm_name']=='CA' and record['res_name']=='GLY'):
|
|
142
|
+
if record['chain'] in [*chain_coords.keys()]:
|
|
143
|
+
chain_coords[record['chain']].append([record['x'],record['y'],record['z']])
|
|
144
|
+
chain_plddt[record['chain']].append(record['B'])
|
|
145
|
+
else:
|
|
146
|
+
chain_coords[record['chain']] = [[record['x'],record['y'],record['z']]]
|
|
147
|
+
chain_plddt[record['chain']] = [record['B']]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
#Convert to arrays
|
|
151
|
+
for chain in chain_coords:
|
|
152
|
+
chain_coords[chain] = np.array(chain_coords[chain])
|
|
153
|
+
chain_plddt[chain] = np.array(chain_plddt[chain])
|
|
154
|
+
|
|
155
|
+
return chain_coords, chain_plddt
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def calc_pdockq(chain_coords, chain_plddt, t):
|
|
159
|
+
'''Calculate the pDockQ scores
|
|
160
|
+
pdockQ = L / (1 + np.exp(-k*(x-x0)))+b
|
|
161
|
+
L= 0.724 x0= 152.611 k= 0.052 and b= 0.018
|
|
162
|
+
|
|
163
|
+
Modified from the calc_pdockq() from FoldDock repo:
|
|
164
|
+
https://gitlab.com/ElofssonLab/FoldDock/-/blob/main/src/pdockq.py#L62
|
|
165
|
+
'''
|
|
166
|
+
|
|
167
|
+
#Get coords and plddt per chain
|
|
168
|
+
ch1, ch2 = [*chain_coords.keys()]
|
|
169
|
+
coords1, coords2 = chain_coords[ch1], chain_coords[ch2]
|
|
170
|
+
plddt1, plddt2 = chain_plddt[ch1], chain_plddt[ch2]
|
|
171
|
+
|
|
172
|
+
#Calc 2-norm
|
|
173
|
+
mat = np.append(coords1, coords2,axis=0)
|
|
174
|
+
a_min_b = mat[:,np.newaxis,:] -mat[np.newaxis,:,:]
|
|
175
|
+
dists = np.sqrt(np.sum(a_min_b.T ** 2, axis=0)).T
|
|
176
|
+
l1 = len(coords1)
|
|
177
|
+
contact_dists = dists[:l1,l1:] #upper triangular --> first dim = chain 1
|
|
178
|
+
contacts = np.argwhere(contact_dists<=t)
|
|
179
|
+
|
|
180
|
+
if contacts.shape[0]<1:
|
|
181
|
+
pdockq=0
|
|
182
|
+
else:
|
|
183
|
+
#Get the average interface plDDT
|
|
184
|
+
avg_if_plddt = np.average(np.concatenate([plddt1[np.unique(contacts[:,0])], plddt2[np.unique(contacts[:,1])]]))
|
|
185
|
+
#Get the number of interface contacts
|
|
186
|
+
n_if_contacts = contacts.shape[0]
|
|
187
|
+
x = avg_if_plddt*np.log10(n_if_contacts)
|
|
188
|
+
pdockq = 0.724 / (1 + np.exp(-0.052*(x-152.611)))+0.018
|
|
189
|
+
|
|
190
|
+
return pdockq
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#Adapted from clean_pdb.py (https://gitlab.com/topf-lab/pi_score/-/tree/master/score_scripts)
|
|
2
|
+
|
|
3
|
+
from Bio.PDB import *
|
|
4
|
+
|
|
5
|
+
dict_aa = {'CYS': 'C', 'ASP': 'D', 'SER': 'S', 'GLN': 'Q', 'LYS': 'K',
|
|
6
|
+
'ILE': 'I', 'PRO': 'P', 'THR': 'T', 'PHE': 'F', 'ASN': 'N',
|
|
7
|
+
'GLY': 'G', 'HIS': 'H', 'LEU': 'L', 'ARG': 'R', 'TRP': 'W',
|
|
8
|
+
'ALA': 'A', 'VAL':'V', 'GLU': 'E', 'TYR': 'Y', 'MET': 'M'}
|
|
9
|
+
|
|
10
|
+
def str_object(pdbfile):
|
|
11
|
+
'''
|
|
12
|
+
Given a pdb file creates a structure object
|
|
13
|
+
'''
|
|
14
|
+
parser = PDBParser(QUIET=True)
|
|
15
|
+
s = parser.get_structure('id', pdbfile)
|
|
16
|
+
return s
|
|
17
|
+
|
|
18
|
+
class SelectResidues(Select):
|
|
19
|
+
""" Only accept the specified residues when saving. """
|
|
20
|
+
def accept_residue(self, residue):
|
|
21
|
+
#print residue.get_resname(),residue.get_full_id()[3][0]
|
|
22
|
+
if residue.get_full_id()[3][0] != 'W' and not residue.get_full_id()[3][0].startswith('H_'):
|
|
23
|
+
if residue.get_resname() in dict_aa.keys():
|
|
24
|
+
return 1
|
|
25
|
+
|
|
26
|
+
def accept_atom(self,atom):
|
|
27
|
+
if not atom.is_disordered() or atom.get_altloc() == 'A':
|
|
28
|
+
if atom.element.strip() != 'H':
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
def change_atloc(pdbfile,
|
|
32
|
+
out=None):
|
|
33
|
+
if out == None:
|
|
34
|
+
out = (pdbfile.rsplit('.')[0]
|
|
35
|
+
+ '_atm_loc'
|
|
36
|
+
+ '.pdb')
|
|
37
|
+
|
|
38
|
+
outfle = open(out,'w')
|
|
39
|
+
with open(pdbfile) as pdb:
|
|
40
|
+
for lne in pdb:
|
|
41
|
+
try:
|
|
42
|
+
if len(lne.split()[3]) >3:
|
|
43
|
+
lne = lne.replace(lne.split()[3],' ' + lne.split()[3][1:])
|
|
44
|
+
elif len(lne.split()[2]) > 3:
|
|
45
|
+
for keys in dict_aa.keys():
|
|
46
|
+
if keys in lne.split()[2]:
|
|
47
|
+
lne = lne.replace(lne.split()[2], lne.split()[2][0:3] + ' ' + lne.split()[2][4:])
|
|
48
|
+
except: pass
|
|
49
|
+
outfle.write(lne)
|
|
50
|
+
outfle.close()
|
|
51
|
+
return out
|
|
52
|
+
|
|
53
|
+
def write_sel_pdb(pdbfile):
|
|
54
|
+
writer = PDBIO()
|
|
55
|
+
struct = str_object(pdbfile)
|
|
56
|
+
writer.set_structure(struct)
|
|
57
|
+
outfle = (pdbfile.rsplit('.',1)[0]
|
|
58
|
+
+ '_clean'
|
|
59
|
+
+ '.pdb')
|
|
60
|
+
writer.save(outfle, select=SelectResidues())
|
|
61
|
+
|
|
62
|
+
return outfle
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#Adapted from interface_assess.py (https://gitlab.com/topf-lab/pi_score/-/tree/master/score_scripts)
|
|
2
|
+
|
|
3
|
+
from Bio.PDB.MMCIFParser import MMCIFParser
|
|
4
|
+
import sys
|
|
5
|
+
from Bio.PDB import Selection, NeighborSearch, PDBParser, Select
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
dict_aa = {'CYS': 'C', 'ASP': 'D', 'SER': 'S', 'GLN': 'Q', 'LYS': 'K',
|
|
9
|
+
'ILE': 'I', 'PRO': 'P', 'THR': 'T', 'PHE': 'F', 'ASN': 'N',
|
|
10
|
+
'GLY': 'G', 'HIS': 'H', 'LEU': 'L', 'ARG': 'R', 'TRP': 'W',
|
|
11
|
+
'ALA': 'A', 'VAL':'V', 'GLU': 'E', 'TYR': 'Y', 'MET': 'M'}
|
|
12
|
+
|
|
13
|
+
class SelectChains(Select):
|
|
14
|
+
""" Only accept the specified chains when saving. """
|
|
15
|
+
def __init__(self, chain_letters):
|
|
16
|
+
self.chain_letters = chain_letters
|
|
17
|
+
|
|
18
|
+
def accept_chain(self, chain):
|
|
19
|
+
return (chain.get_id() in self.chain_letters)
|
|
20
|
+
|
|
21
|
+
def str_object(pdbfile):
|
|
22
|
+
'''
|
|
23
|
+
Given a pdb file creates a structure object
|
|
24
|
+
'''
|
|
25
|
+
if pdbfile.rsplit('.')[-1] == 'pdb':
|
|
26
|
+
parser = PDBParser(QUIET=True)
|
|
27
|
+
elif pdbfile.rsplit('.')[-1] == 'ent':
|
|
28
|
+
parser = PDBParser(QUIET=True)
|
|
29
|
+
elif pdbfile.rsplit('.')[0] == 'cif':
|
|
30
|
+
parser = MMCIFParser()
|
|
31
|
+
else:
|
|
32
|
+
print 'Not a valid PDB format'
|
|
33
|
+
sys.exit()
|
|
34
|
+
structure = parser.get_structure('id', pdbfile)
|
|
35
|
+
return structure
|
|
36
|
+
|
|
37
|
+
def get_num_chains(structure):
|
|
38
|
+
'''
|
|
39
|
+
Returns a list of chain objects in a structure
|
|
40
|
+
'''
|
|
41
|
+
ch_list = Selection.unfold_entities(structure, 'C')
|
|
42
|
+
return ch_list
|
|
43
|
+
|
|
44
|
+
def get_CAatoms(chain_object):
|
|
45
|
+
'''
|
|
46
|
+
for a given chain object, returns a list of CA atoms
|
|
47
|
+
'''
|
|
48
|
+
ca_list = []
|
|
49
|
+
atm_list = Selection.unfold_entities(chain_object, 'A')
|
|
50
|
+
for a in atm_list:
|
|
51
|
+
if a.get_id() == 'CA':
|
|
52
|
+
ca_list.append(a)
|
|
53
|
+
return ca_list
|
|
54
|
+
|
|
55
|
+
def interface_residues(pdbfile,
|
|
56
|
+
len_chains,
|
|
57
|
+
numres_cut,
|
|
58
|
+
dist_cutoff):
|
|
59
|
+
'''
|
|
60
|
+
Given a PDB file calculates interface residues
|
|
61
|
+
'''
|
|
62
|
+
# numres_cut = int(numres_cut)
|
|
63
|
+
structure = str_object(pdbfile)
|
|
64
|
+
ch_list = get_num_chains(structure)
|
|
65
|
+
int_reslist_j = []
|
|
66
|
+
int_reslist_i = []
|
|
67
|
+
dict_intf = {}
|
|
68
|
+
dict_residue_contacts = {}
|
|
69
|
+
for i in xrange(0,len(ch_list)-1):
|
|
70
|
+
for j in xrange(i+1,len(ch_list)):
|
|
71
|
+
int_reslist_j = []
|
|
72
|
+
int_reslist_i = []
|
|
73
|
+
intf_ch = ch_list[j].get_id() + '_' + ch_list[i].get_id()
|
|
74
|
+
ca_i = get_CAatoms(ch_list[i])
|
|
75
|
+
ca_j = get_CAatoms(ch_list[j])
|
|
76
|
+
# print ca_i, intf_ch
|
|
77
|
+
if len(ca_i) <len_chains or len(ca_j) <len_chains:
|
|
78
|
+
# dict_intf = {}
|
|
79
|
+
# dict_residue_contacts = {}
|
|
80
|
+
continue
|
|
81
|
+
ns_i = NeighborSearch(ca_i)
|
|
82
|
+
for atms in ca_j:
|
|
83
|
+
n = ns_i.search(atms.get_coord(), dist_cutoff,'R')
|
|
84
|
+
if len(n) >0 :
|
|
85
|
+
res = (str(atms.get_parent().get_resname())
|
|
86
|
+
+ str(atms.get_parent().get_id()[1]))
|
|
87
|
+
int_reslist_j.append(res)
|
|
88
|
+
t = []
|
|
89
|
+
for at in n:
|
|
90
|
+
res1 = (str(at.get_resname())
|
|
91
|
+
+ str(at.get_id()[1]))
|
|
92
|
+
int_reslist_i.append(res1)
|
|
93
|
+
t.append(res1)
|
|
94
|
+
if intf_ch in dict_residue_contacts.keys():
|
|
95
|
+
dict_residue_contacts[intf_ch].update({res:t})
|
|
96
|
+
else:
|
|
97
|
+
dict_residue_contacts[intf_ch] = {res:t}
|
|
98
|
+
#Number of interface residues from each chain is >=10
|
|
99
|
+
if len(set(int_reslist_j)) >= numres_cut and len(set(int_reslist_i)) >=numres_cut:
|
|
100
|
+
dict_intf[intf_ch] = [list(set(int_reslist_j)),list(set(int_reslist_i))]
|
|
101
|
+
intf_outfle_prefix = pdbfile.split('.')[0]
|
|
102
|
+
intf_outfle_name = intf_outfle_prefix + '_interface_residues_dict.json'
|
|
103
|
+
|
|
104
|
+
if dict_intf:
|
|
105
|
+
with open(intf_outfle_name,'w') as outfle:
|
|
106
|
+
json.dump(dict_intf,outfle)
|
|
107
|
+
return dict_intf, dict_residue_contacts
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def polar_residues(reslist):
|
|
111
|
+
assert len(reslist) >0
|
|
112
|
+
polar_ref = ['SER',
|
|
113
|
+
'THR',
|
|
114
|
+
'ASN',
|
|
115
|
+
'GLN',
|
|
116
|
+
'HIS',
|
|
117
|
+
'TYR']
|
|
118
|
+
polar_reslist = []
|
|
119
|
+
for r in reslist:
|
|
120
|
+
if r in polar_ref:
|
|
121
|
+
polar_reslist.append(r)
|
|
122
|
+
frac_polar_residue = len(polar_reslist)/float(len(reslist))
|
|
123
|
+
return frac_polar_residue
|
|
124
|
+
|
|
125
|
+
def hydrophobic_residues(reslist):
|
|
126
|
+
assert len(reslist) >0
|
|
127
|
+
hydro_ref = ['ALA',
|
|
128
|
+
'LEU',
|
|
129
|
+
'ILE',
|
|
130
|
+
'VAL',
|
|
131
|
+
'PHE',
|
|
132
|
+
'TRP',
|
|
133
|
+
'CYS',
|
|
134
|
+
'MET'
|
|
135
|
+
]
|
|
136
|
+
hydro_reslist = []
|
|
137
|
+
for r in reslist:
|
|
138
|
+
if r in hydro_ref:
|
|
139
|
+
hydro_reslist.append(r)
|
|
140
|
+
frac_hydro_residue = len(hydro_reslist)/float(len(reslist))
|
|
141
|
+
return frac_hydro_residue
|
|
142
|
+
|
|
143
|
+
def charged_residues(reslist):
|
|
144
|
+
assert len(reslist) >0
|
|
145
|
+
charged_ref = ['LYS',
|
|
146
|
+
'ARG',
|
|
147
|
+
'ASP',
|
|
148
|
+
'GLU']
|
|
149
|
+
charged_reslist = []
|
|
150
|
+
for r in reslist:
|
|
151
|
+
if r in charged_ref:
|
|
152
|
+
charged_reslist.append(r)
|
|
153
|
+
frac_charged_residue = len(charged_reslist)/float(len(reslist))
|
|
154
|
+
return frac_charged_residue
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
#Adapted from utils.py (https://gitlab.com/topf-lab/pi_score/-/tree/master/score_scripts)
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pickle
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
def write_csv_with_features_wc_2(indir,outfle):
|
|
11
|
+
out_csv = outfle
|
|
12
|
+
lst_features = ['Num_intf_residues', 'Polar', 'Hydrophobhic', 'Charged']
|
|
13
|
+
outfle = open(out_csv,'w')
|
|
14
|
+
#writing header in csv file
|
|
15
|
+
outfle.write('pdb,interface,')
|
|
16
|
+
for features in lst_features:
|
|
17
|
+
outfle.write(features + ',')
|
|
18
|
+
outfle.write('contact_pairs')
|
|
19
|
+
outfle.write(',sc,hb,sb,int_solv_en,int_area,pvalue')
|
|
20
|
+
outfle.write('\n')
|
|
21
|
+
for fle in os.listdir(indir):
|
|
22
|
+
if os.path.isdir(os.path.join(indir,fle)):
|
|
23
|
+
intf_dict = ''
|
|
24
|
+
cons = {}
|
|
25
|
+
pisa_dict = {}
|
|
26
|
+
dict_num_contacts = {}
|
|
27
|
+
sc_dict = {}
|
|
28
|
+
|
|
29
|
+
for j in os.listdir(os.path.join(indir,fle)):
|
|
30
|
+
nw_path = os.path.join(os.path.join(indir,fle),j)
|
|
31
|
+
if not os.path.isfile(nw_path):
|
|
32
|
+
continue
|
|
33
|
+
if not nw_path.endswith('json'):
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
if nw_path.endswith('_interface_chain_contacts.json'):
|
|
37
|
+
contacts_dict = nw_path
|
|
38
|
+
dict_num_contacts = count_contacts_at_interface(contacts_dict)
|
|
39
|
+
|
|
40
|
+
elif nw_path.endswith('interface_properties_dict.json'):
|
|
41
|
+
intf_dict = nw_path
|
|
42
|
+
|
|
43
|
+
elif nw_path.endswith('sc_scores.json'):
|
|
44
|
+
sc_dict1 = nw_path
|
|
45
|
+
with open(sc_dict1,'rb') as handle:
|
|
46
|
+
sc_dict = json.load(handle)
|
|
47
|
+
elif nw_path.endswith('dict_pisa.json'):
|
|
48
|
+
with open(nw_path) as handle:
|
|
49
|
+
pisa_dict = json.load(handle)
|
|
50
|
+
if intf_dict:
|
|
51
|
+
with open(intf_dict) as handle:
|
|
52
|
+
dict_intf_prop = json.load(handle)
|
|
53
|
+
for intf in dict_intf_prop:
|
|
54
|
+
outfle.write(fle + ',' + intf + ',')
|
|
55
|
+
for feature in lst_features:
|
|
56
|
+
if feature == lst_features[0]:
|
|
57
|
+
outfle.write(str(dict_intf_prop[intf][feature]) + ',')
|
|
58
|
+
else:
|
|
59
|
+
try:
|
|
60
|
+
outfle.write(str(round(dict_intf_prop[intf][feature],3)) + ',')
|
|
61
|
+
except:
|
|
62
|
+
outfle.write('NA' + ',')
|
|
63
|
+
intf1 = intf.strip().split('_')[-1] + '_' + intf.strip().split('_')[0]
|
|
64
|
+
if dict_num_contacts:
|
|
65
|
+
outfle.write(str(dict_num_contacts[intf]) + ',')
|
|
66
|
+
else:
|
|
67
|
+
outfle.write('NA,')
|
|
68
|
+
if sc_dict:
|
|
69
|
+
for pdbid_sc in sc_dict.keys():
|
|
70
|
+
if intf in sc_dict[pdbid_sc].keys() and len(sc_dict[pdbid_sc][intf]) > 0:
|
|
71
|
+
outfle.write(str(sc_dict[pdbid_sc][intf]) + ',')
|
|
72
|
+
elif intf1 in sc_dict[pdbid_sc].keys() and len(sc_dict[pdbid_sc][intf1]) > 0:
|
|
73
|
+
outfle.write(str(sc_dict[pdbid_sc][intf1]) + ',')
|
|
74
|
+
else:
|
|
75
|
+
outfle.write('NA,')
|
|
76
|
+
else:
|
|
77
|
+
outfle.write('NA,')
|
|
78
|
+
|
|
79
|
+
if pisa_dict:
|
|
80
|
+
k = ''
|
|
81
|
+
if intf in pisa_dict.keys():
|
|
82
|
+
k = intf
|
|
83
|
+
elif intf1 in pisa_dict.keys():
|
|
84
|
+
k = intf1
|
|
85
|
+
if k:
|
|
86
|
+
try:
|
|
87
|
+
outfle.write(str(pisa_dict[k]['hb']) + ',')
|
|
88
|
+
except:
|
|
89
|
+
outfle.write('NA,')
|
|
90
|
+
try:
|
|
91
|
+
outfle.write(str(pisa_dict[k]['sb']) + ',')
|
|
92
|
+
except:
|
|
93
|
+
outfle.write('NA,')
|
|
94
|
+
try:
|
|
95
|
+
outfle.write(str(pisa_dict[k]['int_solv_en']) + ',')
|
|
96
|
+
except:
|
|
97
|
+
outfle.write('NA,')
|
|
98
|
+
try:
|
|
99
|
+
outfle.write(str(pisa_dict[k]['int_area']) + ',')
|
|
100
|
+
except:
|
|
101
|
+
outfle.write('NA,')
|
|
102
|
+
try:
|
|
103
|
+
outfle.write(str(pisa_dict[k]['pvalue']))
|
|
104
|
+
except:
|
|
105
|
+
outfle.write('NA')
|
|
106
|
+
else:
|
|
107
|
+
outfle.write('NA,NA,NA,NA,NA')
|
|
108
|
+
outfle.write('\n')
|
|
109
|
+
outfle.close()
|
|
110
|
+
|
|
111
|
+
def write_csv_with_features_wc(indir,outfle):
|
|
112
|
+
out_csv = outfle
|
|
113
|
+
lst_json_fles = []
|
|
114
|
+
lst_features = ['Num_intf_residues', 'Polar', 'Hydrophobhic', 'Charged']
|
|
115
|
+
outfle = open(out_csv,'w')
|
|
116
|
+
#writing header in csv file
|
|
117
|
+
outfle.write('pdb,interface,')
|
|
118
|
+
for features in lst_features:
|
|
119
|
+
outfle.write(features + ',')
|
|
120
|
+
outfle.write('contact_pairs')
|
|
121
|
+
outfle.write(', sc, hb, sb, int_solv_en, int_area, pvalue')
|
|
122
|
+
outfle.write('\n')
|
|
123
|
+
for fle in os.listdir(indir):
|
|
124
|
+
if os.path.isdir(os.path.join(indir,fle)):
|
|
125
|
+
intf_dict = ''
|
|
126
|
+
cons = {}
|
|
127
|
+
pisa_dict = {}
|
|
128
|
+
dict_num_contacts = {}
|
|
129
|
+
complete_sc_dict = {}
|
|
130
|
+
|
|
131
|
+
for j in os.listdir(os.path.join(indir,fle)):
|
|
132
|
+
nw_path = os.path.join(os.path.join(indir,fle),j)
|
|
133
|
+
if not os.path.isfile(nw_path):
|
|
134
|
+
continue
|
|
135
|
+
if not nw_path.endswith('json'):
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
if nw_path.endswith('_interface_chain_contacts.json'):
|
|
139
|
+
contacts_dict = nw_path
|
|
140
|
+
dict_num_contacts = count_contacts_at_interface(contacts_dict)
|
|
141
|
+
|
|
142
|
+
elif nw_path.endswith('interface_properties_dict.json'):
|
|
143
|
+
intf_dict = nw_path
|
|
144
|
+
|
|
145
|
+
elif nw_path.endswith('sc_scores.json'):
|
|
146
|
+
with open(nw_path,'rb') as handle:
|
|
147
|
+
sc_dict = json.load(handle)
|
|
148
|
+
for pdbid, intf_dict_sc in sc_dict.items():
|
|
149
|
+
if pdbid not in complete_sc_dict:
|
|
150
|
+
complete_sc_dict[pdbid] = {}
|
|
151
|
+
complete_sc_dict[pdbid].update(intf_dict_sc)
|
|
152
|
+
|
|
153
|
+
elif nw_path.endswith('dict_pisa.json'):
|
|
154
|
+
with open(nw_path) as handle:
|
|
155
|
+
pisa_dict = json.load(handle)
|
|
156
|
+
|
|
157
|
+
if intf_dict:
|
|
158
|
+
with open(intf_dict) as handle:
|
|
159
|
+
dict_intf_prop = json.load(handle)
|
|
160
|
+
for intf in dict_intf_prop:
|
|
161
|
+
outfle.write(fle + ',' + intf + ',')
|
|
162
|
+
for feature in lst_features:
|
|
163
|
+
if feature == lst_features[0]:
|
|
164
|
+
outfle.write(str(dict_intf_prop[intf][feature]) + ',')
|
|
165
|
+
else:
|
|
166
|
+
try:
|
|
167
|
+
outfle.write(str(round(dict_intf_prop[intf][feature],3)) + ',')
|
|
168
|
+
except:
|
|
169
|
+
outfle.write('NA' + ',')
|
|
170
|
+
#if cons:
|
|
171
|
+
# try:
|
|
172
|
+
# outfle.write(str(round(cons[intf],3)) + ',')
|
|
173
|
+
# except:
|
|
174
|
+
# outfle.write('NA'+ ',')
|
|
175
|
+
#else:
|
|
176
|
+
# outfle.write('NA'+ ',')
|
|
177
|
+
intf1 = intf.strip().split('_')[-1] + '_' + intf.strip().split('_')[0]
|
|
178
|
+
if dict_num_contacts:
|
|
179
|
+
outfle.write(str(dict_num_contacts[intf]) + ',')
|
|
180
|
+
else:
|
|
181
|
+
outfle.write('NA,')
|
|
182
|
+
sc_val = 'NA'
|
|
183
|
+
for pdbid_sc, intf_sc_dict in complete_sc_dict.items():
|
|
184
|
+
if intf in intf_sc_dict:
|
|
185
|
+
sc_val = intf_sc_dict[intf]
|
|
186
|
+
break
|
|
187
|
+
elif intf1 in intf_sc_dict:
|
|
188
|
+
sc_val = intf_sc_dict[intf1]
|
|
189
|
+
break
|
|
190
|
+
outfle.write(sc_val+",")
|
|
191
|
+
|
|
192
|
+
if pisa_dict:
|
|
193
|
+
k = ''
|
|
194
|
+
if intf in pisa_dict.keys():
|
|
195
|
+
k = intf
|
|
196
|
+
elif intf1 in pisa_dict.keys():
|
|
197
|
+
k = intf1
|
|
198
|
+
if k:
|
|
199
|
+
try:
|
|
200
|
+
outfle.write(str(pisa_dict[k]['hb']) + ',')
|
|
201
|
+
except:
|
|
202
|
+
outfle.write('NA,')
|
|
203
|
+
try:
|
|
204
|
+
outfle.write(str(pisa_dict[k]['sb']) + ',')
|
|
205
|
+
except:
|
|
206
|
+
outfle.write('NA,')
|
|
207
|
+
try:
|
|
208
|
+
outfle.write(str(pisa_dict[k]['int_solv_en']) + ',')
|
|
209
|
+
except:
|
|
210
|
+
outfle.write('NA,')
|
|
211
|
+
try:
|
|
212
|
+
outfle.write(str(pisa_dict[k]['int_area']) + ',')
|
|
213
|
+
except:
|
|
214
|
+
outfle.write('NA,')
|
|
215
|
+
try:
|
|
216
|
+
outfle.write(str(pisa_dict[k]['pvalue']))
|
|
217
|
+
except:
|
|
218
|
+
outfle.write('NA')
|
|
219
|
+
else:
|
|
220
|
+
outfle.write('NA,NA,NA,NA,NA')
|
|
221
|
+
outfle.write('\n')
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def count_contacts_at_interface(contacts_dict):
|
|
225
|
+
dict_num_contacts = {}
|
|
226
|
+
with open(contacts_dict,'rb') as handle:
|
|
227
|
+
dict_contacts = json.load(handle)
|
|
228
|
+
#print dict_contacts
|
|
229
|
+
for intf_name in dict_contacts:
|
|
230
|
+
ct = 0
|
|
231
|
+
for ch1_res in dict_contacts[intf_name].keys():
|
|
232
|
+
for ch2_res in dict_contacts[intf_name][ch1_res]:
|
|
233
|
+
ct += 1
|
|
234
|
+
dict_num_contacts[intf_name] = ct
|
|
235
|
+
return dict_num_contacts
|
|
236
|
+
|
|
237
|
+
def filter_csv(csvfile,outfile):
|
|
238
|
+
'''
|
|
239
|
+
Takes the CSV file as input and does a sanity check that all features are computed
|
|
240
|
+
'''
|
|
241
|
+
if os.path.isfile(outfile):
|
|
242
|
+
os.remove(outfile)
|
|
243
|
+
out = open(outfile,'w')
|
|
244
|
+
with open(csvfile,'r') as infile:
|
|
245
|
+
for lne in infile:
|
|
246
|
+
if 'NA' not in lne:
|
|
247
|
+
out.write(lne)
|
|
248
|
+
out.close()
|
|
249
|
+
|
|
250
|
+
def make_predictions(saved_sc, csvfile, saved_model, outfle, session_id):
|
|
251
|
+
with open(saved_model,'rb') as file:
|
|
252
|
+
clf_m = pickle.load(file)
|
|
253
|
+
|
|
254
|
+
topredict = pd.read_csv(csvfile)
|
|
255
|
+
if topredict.empty:
|
|
256
|
+
print 'All features could not be calculated successfully for atleast one of the interfaces!'
|
|
257
|
+
print 'Exiting'
|
|
258
|
+
sys.exit(1)
|
|
259
|
+
topredict_1 = topredict.drop(['pdb','interface','Num_intf_residues'], axis=1)
|
|
260
|
+
with open(saved_sc, 'rb') as file:
|
|
261
|
+
sc = pickle.load(file)
|
|
262
|
+
topredict_1 = np.nan_to_num(sc.transform(topredict_1))
|
|
263
|
+
|
|
264
|
+
pred_em = clf_m.predict(topredict_1)
|
|
265
|
+
dec = clf_m.decision_function(topredict_1)
|
|
266
|
+
|
|
267
|
+
out = open(outfle, 'w')
|
|
268
|
+
out.write('#PDB,chains,predicted_class,pi_score\n')
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
pdb_em = topredict['pdb']
|
|
272
|
+
pdb_em_int = topredict['interface']
|
|
273
|
+
|
|
274
|
+
for i in range(len(topredict_1)):
|
|
275
|
+
out.write(str(pdb_em[i]) + ',' +
|
|
276
|
+
str(pdb_em_int[i]) + ',' +
|
|
277
|
+
str(pred_em[i]) + ',' +
|
|
278
|
+
str(round(dec[i],2)) + '\n')
|
|
279
|
+
out.close()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#Adapted from pisa_utils.py (https://gitlab.com/topf-lab/pi_score/-/tree/master/score_scripts)
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import uuid
|
|
6
|
+
import subprocess
|
|
7
|
+
|
|
8
|
+
def run_pisa(pdbfile=None):
|
|
9
|
+
assert pdbfile is not None
|
|
10
|
+
|
|
11
|
+
session_id = uuid.uuid4().hex[:8]
|
|
12
|
+
outfle = pdbfile.rsplit('.pdb',1)[0] + '_pisa_' + session_id + '.xml'
|
|
13
|
+
|
|
14
|
+
# lancer pisa avec session unique
|
|
15
|
+
cmds = [
|
|
16
|
+
'pisa %s -analyse %s' % (session_id, pdbfile),
|
|
17
|
+
'pisa %s -xml interfaces > %s' % (session_id, outfle),
|
|
18
|
+
'pisa %s -erase' % (session_id)
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
for i, cmd in enumerate(cmds):
|
|
22
|
+
proc = subprocess.Popen(cmd, shell=True, stderr=subprocess.STDOUT,close_fds=True)
|
|
23
|
+
proc.wait()
|
|
24
|
+
return outfle
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def parse_pisa_xml_outfle(xml_fle,outfle_name=None):
|
|
28
|
+
import xml.etree.ElementTree as ET
|
|
29
|
+
intf_area = ''
|
|
30
|
+
pvalue = ''
|
|
31
|
+
energy = ''
|
|
32
|
+
hb = ''
|
|
33
|
+
sb = ''
|
|
34
|
+
dict_pisa = {}
|
|
35
|
+
if outfle_name == None:
|
|
36
|
+
outfle_name = xml_fle.split('_pisa')[0] + '_dict_pisa.json'
|
|
37
|
+
try:
|
|
38
|
+
root = ET.parse(xml_fle).getroot()
|
|
39
|
+
for interface in root.findall('interface'):
|
|
40
|
+
intf_ch = []
|
|
41
|
+
intf_area = "%.2f" % float(interface.find('int_area').text)
|
|
42
|
+
pvalue = "%.2f" % float(interface.find('pvalue').text)
|
|
43
|
+
energy = "%.2f" % float(interface.find('int_solv_en').text)
|
|
44
|
+
for mol in interface.findall('molecule'):
|
|
45
|
+
mol1 = mol.find('chain_id').text
|
|
46
|
+
intf_ch.append(mol1)
|
|
47
|
+
intf_chains = '_'.join(intf_ch)
|
|
48
|
+
dict_pisa[intf_chains] = {}
|
|
49
|
+
for hbonds in interface.findall('h-bonds'):
|
|
50
|
+
hb = int(hbonds.find('n_bonds').text)
|
|
51
|
+
for sb in interface.findall('salt-bridges'):
|
|
52
|
+
sb = int(sb.find('n_bonds').text)
|
|
53
|
+
dict_pisa[intf_chains]['int_area'] = intf_area
|
|
54
|
+
dict_pisa[intf_chains]['pvalue'] = pvalue
|
|
55
|
+
dict_pisa[intf_chains]['int_solv_en'] = energy
|
|
56
|
+
dict_pisa[intf_chains]['hb'] = hb
|
|
57
|
+
dict_pisa[intf_chains]['sb'] = sb
|
|
58
|
+
except:
|
|
59
|
+
root = []
|
|
60
|
+
pass
|
|
61
|
+
if dict_pisa:
|
|
62
|
+
with open(outfle_name,'w') as outfle:
|
|
63
|
+
json.dump(dict_pisa,outfle)
|
|
64
|
+
return dict_pisa
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#Adapted from run_piscore_wc.py (https://gitlab.com/topf-lab/pi_score/-/tree/master/score_scripts)
|
|
2
|
+
#code in python 2.7
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
from interface_assess import *
|
|
7
|
+
from sc_utils import write_sc_script, run_sc
|
|
8
|
+
from clean_pdb import write_sel_pdb, change_atloc
|
|
9
|
+
from pisa_utils import run_pisa, parse_pisa_xml_outfle
|
|
10
|
+
from pi_score_utils import write_csv_with_features_wc, make_predictions, filter_csv
|
|
11
|
+
import time
|
|
12
|
+
import sys
|
|
13
|
+
import uuid
|
|
14
|
+
|
|
15
|
+
author = 'Author: Sony Malhotra '
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
parser = argparse.ArgumentParser(description="Calculate PI-score for a given complex structure")
|
|
19
|
+
group = parser.add_mutually_exclusive_group(required=True)
|
|
20
|
+
group.add_argument("-p", "--pdb", help="PDB file to calculate the PI-score", default=None)
|
|
21
|
+
group.add_argument("-d", "--dirc", help="directory to assess the PDB files",default=None)
|
|
22
|
+
parser.add_argument("-ch", "--chains", help="Chains forming the interface which needs to be assessed",default=None)
|
|
23
|
+
parser.add_argument("-dc", "--distance_cutoff", help="Distance cutoff for interface definition",default=7, type =float)
|
|
24
|
+
parser.add_argument("-s", "--intf_size", help="Number of interface residues from each of the interacting subunits",default=10,type=int)
|
|
25
|
+
parser.add_argument("-ps", "--prot_size", help="Length of each of the chains",default=30,type=int)
|
|
26
|
+
parser.add_argument("-np", "--num_processors", help="Number of processors to use",default=40,type=int)
|
|
27
|
+
parser.add_argument("-o", "--out", help="Name of the output directory to write results",default=os.path.join(os.getcwd(),'pi_output'))
|
|
28
|
+
parser.add_argument("-c","--csv",help="Name of the CSV files where features will be stored",default=None)
|
|
29
|
+
parser.add_argument("-m","--model",help="SVM model to make new predictions",choices=['A','B','WC'], default='WC')
|
|
30
|
+
parser.add_argument("-r","--results",help="Name of the file where model predictions will be written",default=None)
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
pdblist = []
|
|
35
|
+
|
|
36
|
+
if args.dirc != None:
|
|
37
|
+
#print ('Setting chains to all chains')
|
|
38
|
+
args.chains = None
|
|
39
|
+
|
|
40
|
+
#print ('*****Selecting model for training*****')
|
|
41
|
+
dirname, filename = os.path.split(os.path.abspath(__file__))
|
|
42
|
+
if args.model == 'A':
|
|
43
|
+
saved_model = os.path.join(os.path.dirname(sys.argv[0]),'svm_model/finalized_model_A.sav')
|
|
44
|
+
saved_sc = os.path.join(dirname,'svm_model/scaler_model_A.sav')
|
|
45
|
+
elif args.model == 'B':
|
|
46
|
+
saved_model = os.path.join(os.path.dirname(sys.argv[0]),'svm_model/finalized_model_B.sav')
|
|
47
|
+
saved_sc = os.path.join(dirname,'svm_model/scaler_model_B.sav')
|
|
48
|
+
if args.model == 'WC':
|
|
49
|
+
saved_model = os.path.join(os.path.dirname(sys.argv[0]),'svm_model/finalized_model_wc.sav')
|
|
50
|
+
saved_sc = os.path.join(dirname,'svm_model/scaler_model_wc.sav')
|
|
51
|
+
working_path = os.getcwd()
|
|
52
|
+
|
|
53
|
+
#print ('*****Setting output directory for results*****')
|
|
54
|
+
if not os.path.isdir(args.out):
|
|
55
|
+
os.mkdir(args.out)
|
|
56
|
+
|
|
57
|
+
session_id = uuid.uuid4().hex[:8]
|
|
58
|
+
|
|
59
|
+
if args.csv is None:
|
|
60
|
+
current_time = time.strftime("%m.%d.%y_%H%M", time.localtime())
|
|
61
|
+
obj = session_id
|
|
62
|
+
args.csv = os.path.join(args.out, "intf_features_%s_%s.csv" % (current_time, session_id))
|
|
63
|
+
|
|
64
|
+
if args.results is None:
|
|
65
|
+
current_time = time.strftime("%m.%d.%y_%H%M", time.localtime())
|
|
66
|
+
args.results = os.path.join(args.out,"pi_score_%s_%s_id.txt" % (current_time, session_id))
|
|
67
|
+
|
|
68
|
+
if os.path.isfile(args.results):
|
|
69
|
+
os.remove(args.results)
|
|
70
|
+
|
|
71
|
+
out = open(args.results,'w')
|
|
72
|
+
out.write('#PDB,chains,predicted_class,pi_score\n')
|
|
73
|
+
out.close()
|
|
74
|
+
|
|
75
|
+
filter_csvfle = os.path.join(args.out,"filter_intf_features_%s_%s.csv" % (current_time, session_id))
|
|
76
|
+
|
|
77
|
+
#print ('*****Setting input for assessment*****')
|
|
78
|
+
#get a list of pdbfiles to score interfaces for
|
|
79
|
+
if args.pdb:
|
|
80
|
+
pdblist = [args.pdb.rsplit('/',1)[-1]]
|
|
81
|
+
elif args.dirc:
|
|
82
|
+
for fl in os.listdir(args.dirc):
|
|
83
|
+
if fl.endswith('pdb'):
|
|
84
|
+
pdblist.append(fl)
|
|
85
|
+
else:
|
|
86
|
+
print ('Not a valid input')
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
#list of directories where to run conservation
|
|
90
|
+
#dir_infiles = []
|
|
91
|
+
#all_conslst = []
|
|
92
|
+
#all_consdir = []
|
|
93
|
+
#ch_lst = []
|
|
94
|
+
|
|
95
|
+
#print ('*****Iterating over each structure to assess*****')
|
|
96
|
+
for pdb in pdblist:
|
|
97
|
+
chains_in = []
|
|
98
|
+
os.chdir(working_path)
|
|
99
|
+
pd = pdb.rsplit('.',1)[0]
|
|
100
|
+
#make an output directory
|
|
101
|
+
if os.path.isdir(os.path.join(args.out,pd)):
|
|
102
|
+
shutil.rmtree(os.path.join(args.out,pd))
|
|
103
|
+
#print ('*****Making results subdirectory specific to each structure in output directory*****')
|
|
104
|
+
#print (os.path.join(args.out,pd))
|
|
105
|
+
os.mkdir(os.path.join(args.out,pd))
|
|
106
|
+
#copy input files
|
|
107
|
+
if args.dirc:
|
|
108
|
+
copy_cmd = 'cp '+ os.path.join(args.dirc,pdb) + ' ' + os.path.join(args.out,pd)
|
|
109
|
+
else:
|
|
110
|
+
copy_cmd = 'cp '+ os.path.join(args.pdb) + ' ' + os.path.join(args.out,pd)
|
|
111
|
+
#print ('*****Doing PDB,',pdb,' *****')
|
|
112
|
+
os.system(copy_cmd)
|
|
113
|
+
os.chdir(os.path.join(args.out,pd))
|
|
114
|
+
#print ('*****Calculating interface*****')
|
|
115
|
+
#Interface calculation
|
|
116
|
+
dict_intf,dict_contact = interface_residues(pdb,
|
|
117
|
+
len_chains=args.prot_size,
|
|
118
|
+
numres_cut=args.intf_size,
|
|
119
|
+
dist_cutoff=args.distance_cutoff)
|
|
120
|
+
intf_outfle_prefix = pd
|
|
121
|
+
if not dict_intf:
|
|
122
|
+
intf_outfle_name = intf_outfle_prefix + '_no_int.txt'
|
|
123
|
+
a = open(intf_outfle_name,'w')
|
|
124
|
+
a.write('No interfaces found')
|
|
125
|
+
a.close()
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
#print ('*****Calculating contacts*****')
|
|
129
|
+
#Writing the contact dictionary, which residue from which chains are in contact
|
|
130
|
+
contact_name = intf_outfle_prefix + '_interface_chain_contacts.json'
|
|
131
|
+
with open(contact_name,'w') as outfle:
|
|
132
|
+
json.dump(dict_contact,outfle)
|
|
133
|
+
if args.chains:
|
|
134
|
+
for c in args.chain:
|
|
135
|
+
chains_in.append(c)
|
|
136
|
+
dict_intf_prop = {}
|
|
137
|
+
|
|
138
|
+
#Write clean pdbfile for shape complementarity
|
|
139
|
+
clean_pdbfile = write_sel_pdb(pdb)
|
|
140
|
+
atm_file = change_atloc(clean_pdbfile)
|
|
141
|
+
os.system('rm -f ' + clean_pdbfile)
|
|
142
|
+
os.system('mv ' + atm_file + ' ' + clean_pdbfile)
|
|
143
|
+
|
|
144
|
+
#print ('*****Iterating over interfaces in structure*****')
|
|
145
|
+
#Iterating over all the interfaces
|
|
146
|
+
index = 0
|
|
147
|
+
for k in dict_intf:
|
|
148
|
+
index+=1
|
|
149
|
+
ch1 = k.split('_')[0]
|
|
150
|
+
ch2 = k.split('_')[-1]
|
|
151
|
+
flag = False
|
|
152
|
+
if args.chains:
|
|
153
|
+
if ch1 in args.chains and ch2 in args.chains:
|
|
154
|
+
flag = True
|
|
155
|
+
break
|
|
156
|
+
else:
|
|
157
|
+
print ('No interfaces between the input chains,', args.chains)
|
|
158
|
+
continue
|
|
159
|
+
#print ('*****Calculating interface features*****')
|
|
160
|
+
if flag or not args.chains:
|
|
161
|
+
ch1_intf_res = dict_intf[k][0]
|
|
162
|
+
ch2_intf_res = dict_intf[k][1]
|
|
163
|
+
dict_intf_prop[k] = {'Intfresidues_ch1':[ch1,len(ch1_intf_res)]}
|
|
164
|
+
dict_intf_prop[k] = {'Intfresidues_ch2':[ch2,len(ch2_intf_res)]}
|
|
165
|
+
total_intf_res = ch1_intf_res + ch2_intf_res
|
|
166
|
+
total_num_intf_res = len(total_intf_res)
|
|
167
|
+
only_res_name_lst = []
|
|
168
|
+
for re in total_intf_res:
|
|
169
|
+
only_res_name_lst.append(re[0:3])
|
|
170
|
+
polar = polar_residues(only_res_name_lst)
|
|
171
|
+
hydro = hydrophobic_residues(only_res_name_lst)
|
|
172
|
+
charged = charged_residues(only_res_name_lst)
|
|
173
|
+
if dict_intf_prop[k]:
|
|
174
|
+
dict_intf_prop[k].update({'Polar':polar, 'Charged': charged, 'Hydrophobhic':hydro, 'Num_intf_residues': total_num_intf_res})
|
|
175
|
+
else:
|
|
176
|
+
dict_intf_prop[k] = {'Polar':polar, 'Charged': charged, 'Hydrophobhic':hydro, 'Num_intf_residues': total_num_intf_res}
|
|
177
|
+
intf_outfle_name = intf_outfle_prefix + '_interface_properties_dict.json'
|
|
178
|
+
with open(intf_outfle_name,'w') as outfle:
|
|
179
|
+
json.dump(dict_intf_prop,outfle)
|
|
180
|
+
|
|
181
|
+
#print ('*****Calculating shape complementarity*****')
|
|
182
|
+
#calculate shape complementarity
|
|
183
|
+
scriptfile = write_sc_script(chain_lst=k.split('_'),
|
|
184
|
+
pdbfile=clean_pdbfile)
|
|
185
|
+
sc_dir = args.out+"/"+pd+"/"+scriptfile
|
|
186
|
+
run_sc(sc_dir)
|
|
187
|
+
#parse_sc_output('tmp_sc.out')
|
|
188
|
+
|
|
189
|
+
#print ('*****Calculating pisa *****')
|
|
190
|
+
#calculate features using pisa
|
|
191
|
+
outfle_name = run_pisa(clean_pdbfile)
|
|
192
|
+
pisa_out = parse_pisa_xml_outfle(outfle_name)
|
|
193
|
+
|
|
194
|
+
os.chdir(working_path)
|
|
195
|
+
|
|
196
|
+
#print ('*****Writing CSV file with features *****')
|
|
197
|
+
# # Write the CSV file with interface features
|
|
198
|
+
|
|
199
|
+
write_csv_with_features_wc(indir=args.out, outfle=args.csv)
|
|
200
|
+
#
|
|
201
|
+
#
|
|
202
|
+
# #filter CSV and have only interfaces where all features were computed successfully
|
|
203
|
+
filter_csv(args.csv,filter_csvfle)
|
|
204
|
+
|
|
205
|
+
#print ('*****Calculating PI-score*****')
|
|
206
|
+
# # #Make predictions
|
|
207
|
+
make_predictions(saved_sc=saved_sc,
|
|
208
|
+
csvfile=filter_csvfle,
|
|
209
|
+
saved_model=saved_model,
|
|
210
|
+
outfle=args.results,
|
|
211
|
+
session_id=session_id)
|
|
212
|
+
if __name__ == '__main__':
|
|
213
|
+
main()
|
|
214
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#Adapted from sc_utils.py (https://gitlab.com/topf-lab/pi_score/-/tree/master/score_scripts)
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import uuid
|
|
6
|
+
import subprocess
|
|
7
|
+
|
|
8
|
+
def write_sc_script(pdbfile,
|
|
9
|
+
chain_lst=None,
|
|
10
|
+
outfle=None,
|
|
11
|
+
):
|
|
12
|
+
'''
|
|
13
|
+
chain_lst should be list of only two chain Ids e.g. [A,B]
|
|
14
|
+
'''
|
|
15
|
+
#print ('Writing sc script', chain_lst)
|
|
16
|
+
assert (chain_lst != None),"Input chain ID list!"
|
|
17
|
+
assert len(chain_lst) == 2, "Input list with only two chain IDs e.g [A,B]"
|
|
18
|
+
if outfle == None:
|
|
19
|
+
outfle = pdbfile + '_' + '_'.join(chain_lst) + '_sc_infle.sh'
|
|
20
|
+
#print (outfle, 'OUTFLE for SC')
|
|
21
|
+
out = open(outfle,'w')
|
|
22
|
+
out.write('#!/bin/bash\n')
|
|
23
|
+
out.write('sc XYZIN ' + pdbfile + ' <<eof \n')
|
|
24
|
+
out.write('MOLECULE 1\nCHAIN ' + chain_lst[0] + '\n' + 'MOLECULE 2\nCHAIN ' + chain_lst[1] + '\nEND\neof')
|
|
25
|
+
out.close()
|
|
26
|
+
os.system('chmod 777 ' + outfle)
|
|
27
|
+
return outfle
|
|
28
|
+
|
|
29
|
+
def run_sc(scriptfile):
|
|
30
|
+
session_id = uuid.uuid4().hex[:8]
|
|
31
|
+
unique_script = "%s_%s.sh" % (scriptfile.rsplit('.', 1)[0], session_id)
|
|
32
|
+
tmp_out = "%s_tmp_sc_%s.out" % (scriptfile.rsplit('.', 1)[0], session_id)
|
|
33
|
+
|
|
34
|
+
subprocess.call(["cp", scriptfile, unique_script])
|
|
35
|
+
subprocess.call(["sed", "-i", "s/session name/session_%s/g" % session_id, unique_script])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
with open(tmp_out, "w") as out_fh:
|
|
40
|
+
proc = subprocess.Popen([unique_script], stdout=out_fh, stderr=subprocess.STDOUT, close_fds=True)
|
|
41
|
+
proc.wait()
|
|
42
|
+
|
|
43
|
+
os.remove(unique_script)
|
|
44
|
+
parse_sc_output(tmp_out)
|
|
45
|
+
|
|
46
|
+
def parse_sc_output(outfle):
|
|
47
|
+
new_name = outfle.rsplit('_tmp_sc.out',1)[0] + '_dict_sc_scores.json'
|
|
48
|
+
if os.path.isfile(new_name):
|
|
49
|
+
with open(new_name) as json_file:
|
|
50
|
+
dict_out = json.load(json_file)
|
|
51
|
+
#else:
|
|
52
|
+
dict_out = {}
|
|
53
|
+
ch_lst = []
|
|
54
|
+
pdb = ''
|
|
55
|
+
sc = ''
|
|
56
|
+
#print(outfle)
|
|
57
|
+
with open(outfle,'r') as out:
|
|
58
|
+
for lne in out:
|
|
59
|
+
if 'Number of atoms selected in chain' in lne:
|
|
60
|
+
ch_lst.append(lne.split('=')[0].split()[-1])
|
|
61
|
+
if 'Logical name: XYZIN File name: ' in lne:
|
|
62
|
+
#pdb = lne.split()[-1][0:4]
|
|
63
|
+
#for em challenge targets
|
|
64
|
+
pdb = lne.split()[-1].split('_clean')[0]
|
|
65
|
+
|
|
66
|
+
if 'Shape complementarity statistic Sc' in lne:
|
|
67
|
+
sc = lne.split('=')[-1].strip()
|
|
68
|
+
try:
|
|
69
|
+
if pdb in dict_out.keys():
|
|
70
|
+
dict_out[pdb].update({'_'.join(ch_lst):sc})
|
|
71
|
+
else:
|
|
72
|
+
dict_out[pdb] = {'_'.join(ch_lst):sc}
|
|
73
|
+
except:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
with open(new_name,'w') as sec_outfle:
|
|
77
|
+
json.dump(dict_out,sec_outfle)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""svm_weight"""
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
Fast_HInt/Fast_HInt.py
|
|
4
|
+
Fast_HInt/File_proteins.py
|
|
5
|
+
Fast_HInt/Scoring_HInt.py
|
|
6
|
+
Fast_HInt/Utils_HInt.py
|
|
7
|
+
Fast_HInt/__init__.py
|
|
8
|
+
Fast_HInt/get_good_inter_pae.py
|
|
9
|
+
Fast_HInt/script_pi_score/__init__.py
|
|
10
|
+
Fast_HInt/script_pi_score/calculate_mpdockq.py
|
|
11
|
+
Fast_HInt/script_pi_score/clean_pdb.py
|
|
12
|
+
Fast_HInt/script_pi_score/interface_assess.py
|
|
13
|
+
Fast_HInt/script_pi_score/pi_score_utils.py
|
|
14
|
+
Fast_HInt/script_pi_score/pisa_utils.py
|
|
15
|
+
Fast_HInt/script_pi_score/run_piscore_wc.py
|
|
16
|
+
Fast_HInt/script_pi_score/sc_utils.py
|
|
17
|
+
Fast_HInt/script_pi_score/svm_model/__init__.py
|
|
18
|
+
Fast_HInt_ppi.egg-info/PKG-INFO
|
|
19
|
+
Fast_HInt_ppi.egg-info/SOURCES.txt
|
|
20
|
+
Fast_HInt_ppi.egg-info/dependency_links.txt
|
|
21
|
+
Fast_HInt_ppi.egg-info/entry_points.txt
|
|
22
|
+
Fast_HInt_ppi.egg-info/requires.txt
|
|
23
|
+
Fast_HInt_ppi.egg-info/top_level.txt
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
README.md
|
|
2
|
-
setup.py
|
|
3
|
-
Fast_HInt/Fast_HInt.py
|
|
4
|
-
Fast_HInt/File_proteins.py
|
|
5
|
-
Fast_HInt/Scoring_HInt.py
|
|
6
|
-
Fast_HInt/Utils_HInt.py
|
|
7
|
-
Fast_HInt/__init__.py
|
|
8
|
-
Fast_HInt/get_good_inter_pae.py
|
|
9
|
-
Fast_HInt_ppi.egg-info/PKG-INFO
|
|
10
|
-
Fast_HInt_ppi.egg-info/SOURCES.txt
|
|
11
|
-
Fast_HInt_ppi.egg-info/dependency_links.txt
|
|
12
|
-
Fast_HInt_ppi.egg-info/entry_points.txt
|
|
13
|
-
Fast_HInt_ppi.egg-info/requires.txt
|
|
14
|
-
Fast_HInt_ppi.egg-info/top_level.txt
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|