-
Notifications
You must be signed in to change notification settings - Fork 24
/
__init__.py
288 lines (239 loc) · 9.08 KB
/
__init__.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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#!/usr/bin/env pymol
'''
PyMOL plugin for US-align
USAGE:
usalign mobile, fix [,args [,exe]]
usalign_msta pdb1, pdb2, pdb3 [...] [,exe=...]
INSTALLATION
Install this script as a PyMOL plugin by
"Plugin" - "Plugin Manager" - "Install New Plugin"
This plugin depends on the binary executable of US-align, which must be
available within a directory specified by PATH. You can get the PATH
value within PyMOL by the following command:
print(os.getenv('PATH'))
On Mac OS, the US-align binary executable can be installed by
conda install -c bioconda usalign
'''
#This script is partly based on tmalign plugin by Thomas Holder available at
#https://github.com/Pymol-Scripts/Pymol-script-repo/blob/master/tmalign.py
from __future__ import print_function
__author__ = 'Chengxin Zhang'
__version__ = '20241201'
__license__ = 'BSD-2-Clause'
from pymol import cmd, CmdException
import subprocess
import tempfile
import os
import platform
def check_executable(exe="USalign"):
try:
process = subprocess.Popen('"'+exe+'"', stdout=subprocess.PIPE, shell=True,
universal_newlines=True)
if "version" in process.stdout.read():
return True
except OSError:
print(exe+" not executable")
return False
print(exe+" not executable")
return False
def get_usalign_path(exe="USalign"):
if platform.system().lower().startswith("win"):
exe+=".exe"
filename = os.path.join(os.path.dirname(os.path.abspath(__file__)),exe)
if os.path.isfile(filename) and check_executable(filename):
return filename
else:
for p in os.getenv("PATH").split(os.pathsep):
filename=os.path.join(p,exe)
if os.path.isfile(filename) and check_executable(filename):
return filename
print("ERROR! Cannot locate %s at %s or at %s"%(exe,
os.path.dirname(os.path.abspath(__file__)),os.getenv("PATH")))
print("Please put the USalign executable at one of the aforementioned paths")
if platform.system().lower().startswith("darwin"):
print("You may install US-align executable by:")
print("conda install -c bioconda usalign")
return exe
def usalign(mobile, target, args='', exe='', transform=1):
'''
USAGE
usalign mobile, target [, args [, exe ]]
ARGUMENTS
mobile, target = string: atom selections
args = string: Extra arguments such as -mm and -byresi
exe = string: Path to USalign executable {default: USalign}
CITATION
Zhang C, Shine M, Pyle AM, Zhang Y (2022) Nat Methods, 19, 1109-1115.
https://github.com/pylelab/USalign
'''
mobile_filename = tempfile.mktemp('.pdb', 'mobile')
target_filename = tempfile.mktemp('.pdb', 'target')
mobile_ca_sele = '(%s) and (not hetatm) and alt +A' % (mobile)
target_ca_sele = '(%s) and (not hetatm) and alt +A' % (target)
if not "-atom" in args:
mobile_ca_sele+=" and (name CA or name C3')"
target_ca_sele+=" and (name CA or name C3')"
cmd.save(mobile_filename, mobile_ca_sele)
cmd.save(target_filename, target_ca_sele)
if len(exe)==0:
exe=get_usalign_path("USalign")
if args=='""':
args=''
if len(args)>2 and args[0]=='"' and args[-1]=='"':
args=args[1:-1]
if not "-outfmt" in args:
args+=" -outfmt -1"
args = ' '.join(['"'+exe+'"', mobile_filename, target_filename, args, '-m -'])
print(args)
try:
process = subprocess.Popen(args, stdout=subprocess.PIPE, shell=True,
universal_newlines=True)
lines = process.stdout.readlines()
except OSError:
print('Cannot execute "%s", please provide full path to USalign executable' % (args))
raise CmdException
finally:
os.remove(mobile_filename)
os.remove(target_filename)
rowcount = 0
matrix = []
for line in iter(lines):
print(line.rstrip())
if line.strip().startswith('------ The rotation matrix to rotate '):
rowcount = 1
elif 4 >= rowcount and rowcount> 0:
if rowcount >= 2:
a = list(map(float, line.split()))
matrix.extend(a[2:5])
matrix.append(a[1])
rowcount += 1
assert len(matrix) == 3 * 4
matrix.extend([0, 0, 0, 1])
if int(transform):
cmd.transform_selection('byobject (%s)' % (mobile), matrix, homogenous=1)
return
def usalign_msta(*args, **kwargs):
'''
USAGE
usalign_msta pdb1, pdb2, pdb3 [...] [,args] [,exe]
ARGUMENTS
pdb1, pdb2, pdb3 ... = string: atom selections
args = string: Extra arguments such as -mm and -byresi
exe = string: Path to USalign executable {default: USalign}
CITATION
Zhang C, Shine M, Pyle AM, Zhang Y (2022) Nat Methods, 19, 1109-1115.
https://github.com/pylelab/USalign
'''
target_list = []
argument = ""
for t,target in enumerate(args):
target_list.append(target)
print("[%d] %s"%(t,target))
exe=''
transform=1
argument=''
for key in kwargs:
if key=="exe":
exe=kwargs[key]
elif key=="transform":
transform=kwargs[key]
elif key=="args":
argument=kwargs[key]
elif "self" in key:
continue
else:
print("ignore keyword argument %s= %s"%(key,kwargs[key]))
if len(target_list)<=1:
print("ERROR! less than three targets two align")
return
elif len(target_list)==2:
print("ERROR! only two targets; please use the 'usalign' command instead")
return
if "-mm " in argument and not "-mm 4" in argument:
print("ERROR! -mm cannot be used with usalign_msta")
return
if "-m " in argument:
print("ERROR! do not set -m for usalign_msta")
return
if "-outfmt " in argument and not "-outfmt -1" in argument and \
not "-outfmt 0" in argument and not "-outfmt 1" in argument:
print("ERROR! use -outfmt 0 with usalign_msta")
return
if len(exe)==0:
exe=get_usalign_path("USalign")
args = argument
if args=='""':
args=''
elif len(args)>2 and args[0]=='"' and args[-1]=='"':
args=args[1:-1]
if not "-outfmt " in args:
args+=" -outfmt 0"
tmpdir = tempfile.mkdtemp(prefix="tmp_msta")
listfile = os.path.join(tmpdir,"list")
matrixfile = os.path.join(tmpdir,"matrix.txt")
fp = open(listfile,'w')
filename_list = []
for t,target in enumerate(target_list):
target_filename = os.path.join(tmpdir, "%d.pdb"%t)
target_ca_sele = '(%s) and (not hetatm) and alt +A' % (target)
if not "-atom " in args:
target_ca_sele+=" and (name CA or name C3')"
cmd.save(target_filename, target_ca_sele)
filename_list.append(target_filename)
fp.write("%d.pdb\n"%t)
fp.close()
args = ' '.join(['"'+exe+'"', "-mm 4 -dir",tmpdir,listfile, args, "-m",matrixfile])
print(args)
try:
process = subprocess.Popen(args, stdout=subprocess.PIPE, shell=True,
universal_newlines=True)
lines = process.stdout.readlines()
for line in iter(lines):
print(line.rstrip())
except OSError:
print('Cannot execute "%s", please provide full path to USalign executable' % (args))
raise CmdException
for target_filename in filename_list:
os.remove(target_filename)
os.remove(listfile)
if not int(transform):
return
fp=open(matrixfile)
matrixtxt=fp.read()
fp.close()
for block in matrixtxt.split('------ The rotation matrix to rotate '):
matrix = []
t = -1
for rowcount,line in enumerate(block.splitlines()):
if rowcount==0 and " to " in line:
target = line.strip().split('.pdb')[0].lstrip('/').lstrip('\\')
t = int(target)
elif rowcount>=5:
break
elif rowcount>=2:
a = list(map(float, line.split()))
matrix.extend(a[2:5])
matrix.append(a[1])
if t==-1:
continue
if len(matrix) != 3*4:
print("len(matrix)=%d != 3*4 for %s"%(len(matrix),target_list[t]))
continue
matrix.extend([0, 0, 0, 1])
print('------ The rotation matrix to rotate '+target_list[t]+' '+block)
cmd.transform_selection('byobject (%s)' % (target_list[t]), matrix, homogenous=1)
return
# pymol commands
cmd.extend('usalign', usalign)
cmd.extend('USalign', usalign)
cmd.extend('usalign_msta', usalign_msta)
cmd.extend('USalign_MSTA', usalign_msta)
# autocompletion
cmd.auto_arg[0].update({ 'usalign': cmd.auto_arg[0]['align'], })
cmd.auto_arg[1].update({ 'usalign': cmd.auto_arg[1]['align'], })
cmd.auto_arg[0].update({ 'USalign': cmd.auto_arg[0]['align'], })
cmd.auto_arg[1].update({ 'USalign': cmd.auto_arg[1]['align'], })
cmd.auto_arg[0].update({ 'usalign_msta': cmd.auto_arg[0]['align'], })
cmd.auto_arg[1].update({ 'usalign_msta': cmd.auto_arg[1]['align'], })
cmd.auto_arg[0].update({ 'USalign_MSTA': cmd.auto_arg[0]['align'], })
cmd.auto_arg[1].update({ 'USalign_MSTA': cmd.auto_arg[1]['align'], })