-
Notifications
You must be signed in to change notification settings - Fork 10
/
show_contacts.py
executable file
·265 lines (196 loc) · 10.9 KB
/
show_contacts.py
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
#!/usr/bin/python
'''PyMOL plugin that provides show_contacts command and GUI
for highlighting good and bad polar contacts. Factored out of
clustermols by Matthew Baumgartner.
The advantage of this package is it requires many fewer dependencies.
'''
from __future__ import print_function
import sys,os
import Pmw
from pymol import cmd
DEBUG=1
def show_contacts(selection,selection2,result="contacts",cutoff=3.6, bigcutoff = 4.0, SC_DEBUG = DEBUG):
"""
USAGE
show_contacts selection, selection2, [result=contacts],[cutoff=3.6],[bigcutoff=4.0]
Show various polar contacts, the good, the bad, and the ugly.
Edit MPB 6-26-14: The distances are heavy atom distances, so I upped the default cutoff to 4.0
Returns:
True/False - if False, something went wrong
"""
if SC_DEBUG > 4:
print('Starting show_contacts')
print('selection = "' + selection + '"')
print('selection2 = "' + selection2 + '"')
#if the group of contacts already exist, delete them
cmd.delete(result)
# ensure only N and O atoms are in the selection
all_don_acc1 = selection + " and (donor or acceptor)"
all_don_acc2 = selection2 + " and (donor or acceptor)"
if SC_DEBUG > 4:
print('all_don_acc1 = "' + all_don_acc1 + '"')
print('all_don_acc2 = "' + all_don_acc2 + '"')
#if theses selections turn out not to have any atoms in them, pymol throws cryptic errors when calling the dist function like:
#'Selector-Error: Invalid selection name'
#So for each one, manually perform the selection and then pass the reference to the distance command and at the end, clean up the selections
#the return values are the count of the number of atoms
all1_sele_count = cmd.select('all_don_acc1_sele', all_don_acc1)
all2_sele_count = cmd.select('all_don_acc2_sele', all_don_acc2)
#print out some warnings
if DEBUG > 3:
if not all1_sele_count:
print('Warning: all_don_acc1 selection empty!')
if not all2_sele_count:
print('Warning: all_don_acc2 selection empty!')
########################################
allres = result + "_all"
if all1_sele_count and all2_sele_count:
cmd.distance(allres, 'all_don_acc1_sele', 'all_don_acc2_sele', bigcutoff, mode = 0)
cmd.set("dash_radius", "0.05", allres)
cmd.set("dash_color", "purple", allres)
cmd.hide("labels", allres)
########################################
#compute good polar interactions according to pymol
polres = result + "_polar"
if all1_sele_count and all2_sele_count:
cmd.distance(polres, 'all_don_acc1_sele', 'all_don_acc2_sele', cutoff, mode = 2) #hopefully this checks angles? Yes
cmd.set("dash_radius","0.126",polres)
########################################
#When running distance in mode=2, the cutoff parameter is ignored if set higher then the default of 3.6
#so set it to the passed in cutoff and change it back when you are done.
old_h_bond_cutoff_center = cmd.get('h_bond_cutoff_center') # ideal geometry
old_h_bond_cutoff_edge = cmd.get('h_bond_cutoff_edge') # minimally acceptable geometry
cmd.set('h_bond_cutoff_center', bigcutoff)
cmd.set('h_bond_cutoff_edge', bigcutoff)
#compute possibly suboptimal polar interactions using the user specified distance
pol_ok_res = result + "_polar_ok"
if all1_sele_count and all2_sele_count:
cmd.distance(pol_ok_res, 'all_don_acc1_sele', 'all_don_acc2_sele', bigcutoff, mode = 2)
cmd.set("dash_radius", "0.06", pol_ok_res)
#now reset the h_bond cutoffs
cmd.set('h_bond_cutoff_center', old_h_bond_cutoff_center)
cmd.set('h_bond_cutoff_edge', old_h_bond_cutoff_edge)
########################################
onlyacceptors1 = selection + " and (acceptor and !donor)"
onlyacceptors2 = selection2 + " and (acceptor and !donor)"
onlydonors1 = selection + " and (!acceptor and donor)"
onlydonors2 = selection2 + " and (!acceptor and donor)"
#perform the selections
onlyacceptors1_sele_count = cmd.select('onlyacceptors1_sele', onlyacceptors1)
onlyacceptors2_sele_count = cmd.select('onlyacceptors2_sele', onlyacceptors2)
onlydonors1_sele_count = cmd.select('onlydonors1_sele', onlydonors1)
onlydonors2_sele_count = cmd.select('onlydonors2_sele', onlydonors2)
#print out some warnings
if SC_DEBUG > 2:
if not onlyacceptors1_sele_count:
print('Warning: onlyacceptors1 selection empty!')
if not onlyacceptors2_sele_count:
print('Warning: onlyacceptors2 selection empty!')
if not onlydonors1_sele_count:
print('Warning: onlydonors1 selection empty!')
if not onlydonors2_sele_count:
print('Warning: onlydonors2 selection empty!')
accres = result+"_aa"
if onlyacceptors1_sele_count and onlyacceptors2_sele_count:
aa_dist_out = cmd.distance(accres, 'onlyacceptors1_sele', 'onlyacceptors2_sele', cutoff, 0)
if aa_dist_out < 0:
print('\n\nCaught a pymol selection error in acceptor-acceptor selection of show_contacts')
print('accres:', accres)
print('onlyacceptors1', onlyacceptors1)
print('onlyacceptors2', onlyacceptors2)
return False
cmd.set("dash_color","red",accres)
cmd.set("dash_radius","0.125",accres)
########################################
donres = result+"_dd"
if onlydonors1_sele_count and onlydonors2_sele_count:
dd_dist_out = cmd.distance(donres, 'onlydonors1_sele', 'onlydonors2_sele', cutoff, 0)
#try to catch the error state
if dd_dist_out < 0:
print('\n\nCaught a pymol selection error in dd selection of show_contacts')
print('donres:', donres)
print('onlydonors1', onlydonors1)
print('onlydonors2', onlydonors2)
print("cmd.distance('" + donres + "', '" + onlydonors1 + "', '" + onlydonors2 + "', " + str(cutoff) + ", 0)")
return False
cmd.set("dash_color","red",donres)
cmd.set("dash_radius","0.125",donres)
##########################################################
##### find the buried unpaired atoms of the receptor #####
##########################################################
#initialize the variable for when CALC_SASA is False
unpaired_atoms = ''
## Group
cmd.group(result,"%s %s %s %s %s %s" % (polres, allres, accres, donres, pol_ok_res, unpaired_atoms))
## Clean up the selection objects
#if the show_contacts debug level is high enough, don't delete them.
if SC_DEBUG < 5:
cmd.delete('all_don_acc1_sele')
cmd.delete('all_don_acc2_sele')
cmd.delete('onlyacceptors1_sele')
cmd.delete('onlyacceptors2_sele')
cmd.delete('onlydonors1_sele')
cmd.delete('onlydonors2_sele')
return True
cmd.extend('contacts', show_contacts) #contacts to avoid clashing with cluster_mols version
#################################################################################
########################### Start of pymol plugin code ##########################
#################################################################################
about_text = '''show_contacts was factored out of the much more full-featured cluster_mols
by Dr. Matt Baumgartner (https://pymolwiki.org/index.php/Cluster_mols). It provides
an easy way to highlight polar contacts (and clashes) between two selections without
requiring the installation of additional dependencies.
'''
class Show_Contacts:
''' Main Pymol Plugin Class '''
def __init__(self, app):
parent = app.root
self.parent = parent
self.app = app
############################################################################################
### Open a window with options to select to loaded objects ###
############################################################################################
self.select_dialog = Pmw.Dialog(parent,
buttons = ('Ok','Cancel'),
title = 'Show Contacts Plugin',
command = self.button_pressed )
self.select_dialog.withdraw()
#allow the user to select from objects already loaded in pymol
self.select_object_combo_box = Pmw.ComboBox(self.select_dialog.interior(),
scrolledlist_items=[],
labelpos='w',
label_text='Select loaded object:',
listbox_height = 2,
dropdown=True)
self.select_object_combo_box2 = Pmw.ComboBox(self.select_dialog.interior(),
scrolledlist_items=[],
labelpos='w',
label_text='Select loaded object:',
listbox_height = 2,
dropdown=True)
self.select_object_combo_box.grid(column=1, row=0)
self.select_object_combo_box2.grid(column=2, row=0)
self.populate_ligand_select_list()
self.select_dialog.show()
def button_pressed(self, result):
if hasattr(result,'keycode'):
if result.keycode == 36:
print('keycode:', result.keycode)
elif result == 'Ok' or result == 'Exit' or result == None:
s1 = self.select_object_combo_box.get()
s2 = self.select_object_combo_box2.get()
show_contacts(s1,s2,'%s_%s'%(s1,s2))
self.select_dialog.withdraw()
elif result == 'Cancel' or result == None:
self.select_dialog.withdraw()
def populate_ligand_select_list(self):
''' Go thourgh the loaded objects in PyMOL and add them to the selected list. '''
#get the loaded objects
loaded_objects = [ name for name in cmd.get_names('all') if '_cluster_' not in name ]
self.select_object_combo_box.clear()
self.select_object_combo_box2.clear()
for ob in loaded_objects:
self.select_object_combo_box.insert('end', ob)
self.select_object_combo_box2.insert('end', ob)
def __init__(self):
self.menuBar.addmenuitem('Plugin', 'command', 'Show Contacts', label = 'Show Contacts', command = lambda s=self : Show_Contacts(s))