1 #!/bin/env python
2 #
3 # File: PyMOLVisualizeInterfaces.py
4 # Author: Manish Sud <msud@san.rr.com>
5 #
6 # Copyright (C) 2025 Manish Sud. All rights reserved.
7 #
8 # The functionality available in this script is implemented using PyMOL, a
9 # molecular visualization system on an open source foundation originally
10 # developed by Warren DeLano.
11 #
12 # This file is part of MayaChemTools.
13 #
14 # MayaChemTools is free software; you can redistribute it and/or modify it under
15 # the terms of the GNU Lesser General Public License as published by the Free
16 # Software Foundation; either version 3 of the License, or (at your option) any
17 # later version.
18 #
19 # MayaChemTools is distributed in the hope that it will be useful, but without
20 # any warranty; without even the implied warranty of merchantability of fitness
21 # for a particular purpose. See the GNU Lesser General Public License for more
22 # details.
23 #
24 # You should have received a copy of the GNU Lesser General Public License
25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
27 # Boston, MA, 02111-1307, USA.
28 #
29
30 from __future__ import print_function
31
32 import os
33 import sys
34 import time
35 import re
36
37 # PyMOL imports...
38 try:
39 import pymol
40
41 # Finish launching PyMOL in a command line mode for batch processing (-c)
42 # along with the following options: disable loading of pymolrc and plugins (-k);
43 # suppress start up messages (-q)
44 pymol.finish_launching(["pymol", "-ckq"])
45 except ImportError as ErrMsg:
46 sys.stderr.write("\nFailed to import PyMOL module/package: %s\n" % ErrMsg)
47 sys.stderr.write("Check/update your PyMOL environment and try again.\n\n")
48 sys.exit(1)
49
50 # MayaChemTools imports...
51 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
52 try:
53 from docopt import docopt
54 import MiscUtil
55 import PyMOLUtil
56 except ImportError as ErrMsg:
57 sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
58 sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
59 sys.exit(1)
60
61 ScriptName = os.path.basename(sys.argv[0])
62 Options = {}
63 OptionsInfo = {}
64
65
66 def main():
67 """Start execution of the script."""
68
69 MiscUtil.PrintInfo(
70 "\n%s (PyMOL v%s; MayaChemTools v%s; %s): Starting...\n"
71 % (ScriptName, pymol.cmd.get_version()[0], MiscUtil.GetMayaChemToolsVersion(), time.asctime())
72 )
73
74 (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
75
76 # Retrieve command line arguments and options...
77 RetrieveOptions()
78
79 # Process and validate command line arguments and options...
80 ProcessOptions()
81
82 # Perform actions required by the script...
83 GenerateMacromolecularInterfacesVisualization()
84
85 MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
86 MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
87
88
89 def GenerateMacromolecularInterfacesVisualization():
90 """Generate visualization for macromolecular interfaces."""
91
92 Outfile = OptionsInfo["PMLOutfile"]
93 OutFH = open(Outfile, "w")
94 if OutFH is None:
95 MiscUtil.PrintError("Failed to open output fie %s " % Outfile)
96
97 MiscUtil.PrintInfo("\nGenerating file %s..." % Outfile)
98
99 # Setup header...
100 WritePMLHeader(OutFH, ScriptName)
101 WritePyMOLParameters(OutFH)
102
103 WriteComplexesAndChainsViews(OutFH)
104 WriteInterfaceViews(OutFH)
105
106 OutFH.close()
107
108 # Generate PSE file as needed...
109 if OptionsInfo["PSEOut"]:
110 GeneratePyMOLSessionFile()
111
112
113 def WriteComplexesAndChainsViews(OutFH):
114 """Write out PML for viewing complexes and chains in input files."""
115
116 # Setup views for input file(s)...
117 for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
118 # Setup PyMOL object names...
119 PyMOLObjectNamesInfo = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex]
120
121 # Setup complex view...
122 WriteComplexView(OutFH, FileIndex, PyMOLObjectNamesInfo)
123
124 # Setup chain views...
125 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
126
127 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
128 WriteChainView(OutFH, FileIndex, PyMOLObjectNamesInfo, ChainID)
129
130 # Setup ligand views...
131 for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
132 WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNamesInfo, ChainID, LigandID)
133
134 # Set up ligand level group...
135 Enable, Action = [True, "close"]
136 GenerateAndWritePMLForGroup(
137 OutFH,
138 PyMOLObjectNamesInfo["Ligands"][ChainID][LigandID]["ChainLigandGroup"],
139 PyMOLObjectNamesInfo["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"],
140 Enable,
141 Action,
142 )
143
144 # Setup Chain level group...
145 Enable, Action = [True, "open"]
146 GenerateAndWritePMLForGroup(
147 OutFH,
148 PyMOLObjectNamesInfo["Chains"][ChainID]["ChainGroup"],
149 PyMOLObjectNamesInfo["Chains"][ChainID]["ChainGroupMembers"],
150 Enable,
151 Action,
152 )
153
154 # Set up complex level group...
155 Enable, Action = [True, "close"]
156 GenerateAndWritePMLForGroup(
157 OutFH, PyMOLObjectNamesInfo["PDBGroup"], PyMOLObjectNamesInfo["PDBGroupMembers"], Enable, Action
158 )
159
160 # Delete empty PyMOL objects...
161 DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNamesInfo)
162
163
164 def WriteInterfaceViews(OutFH):
165 """Write out PML for viewing macromolecular interfaces among specified chains."""
166
167 InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
168 if InterfaceChainsAndResiduesInfo is None:
169 return
170
171 PyMOLInterfaceObjectNamesInfo = OptionsInfo["InfilesInfo"]["PyMOLInterfaceObjectNamesInfo"]
172 InterfaceChainPairsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainPairsAndResiduesInfo"]
173
174 FirstInterfaceID = True
175 for InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
176 WriteInterfacePolarContactsView(
177 OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLInterfaceObjectNamesInfo
178 )
179 WriteInterfaceHydrophobicContactsView(
180 OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLInterfaceObjectNamesInfo
181 )
182
183 for InterfaceChainID in InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID]:
184 ChainID = InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID]
185 ResNums = InterfaceChainsAndResiduesInfo["ChainIDsResNums"][InterfaceID][InterfaceChainID]
186 ComplexName = InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"][InterfaceID][InterfaceChainID]
187 FileIndex = InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID]
188
189 WriteInterfaceChainView(
190 OutFH,
191 FileIndex,
192 InterfaceID,
193 InterfaceChainID,
194 ChainID,
195 ResNums,
196 ComplexName,
197 PyMOLInterfaceObjectNamesInfo,
198 )
199
200 # Setup interface Chain level group...
201 Enable, Action = [True, "open"]
202 GenerateAndWritePMLForGroup(
203 OutFH,
204 PyMOLInterfaceObjectNamesInfo["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroup"],
205 PyMOLInterfaceObjectNamesInfo["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"],
206 Enable,
207 Action,
208 )
209
210 if FirstInterfaceID:
211 FirstInterfaceID = False
212 Enable, Action = [True, "open"]
213 else:
214 Enable, Action = [True, "close"]
215
216 GenerateAndWritePMLForGroup(
217 OutFH,
218 PyMOLInterfaceObjectNamesInfo["InterfaceIDs"][InterfaceID]["InterfaceIDGroup"],
219 PyMOLInterfaceObjectNamesInfo["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"],
220 Enable,
221 Action,
222 )
223
224 # Setup interfaces level group...
225 Enable, Action = [True, "open"]
226 GenerateAndWritePMLForGroup(
227 OutFH,
228 PyMOLInterfaceObjectNamesInfo["InterfacesGroup"],
229 PyMOLInterfaceObjectNamesInfo["InterfacesGroupMembers"],
230 Enable,
231 Action,
232 )
233
234 DeleteEmptyPyMOLInterfaceObjects(OutFH)
235
236 # Setup orientation...
237 OutFH.write("""\ncmd.orient("visible", animate = -1)\n""")
238
239
240 def WritePMLHeader(OutFH, ScriptName):
241 """Write out PML setting up complex view."""
242
243 HeaderInfo = PyMOLUtil.SetupPMLHeaderInfo(ScriptName)
244 OutFH.write("%s\n" % HeaderInfo)
245
246
247 def WritePyMOLParameters(OutFH):
248 """Write out PyMOL global parameters."""
249
250 PMLCmds = []
251 PMLCmds.append("""cmd.set("transparency", %.2f, "", 0)""" % (OptionsInfo["SurfaceTransparency"]))
252 PMLCmds.append("""cmd.set("label_font_id", %s)""" % (OptionsInfo["LabelFontID"]))
253 PML = "\n".join(PMLCmds)
254
255 OutFH.write("""\n""\n"Setting up PyMOL gobal parameters..."\n""\n""")
256 OutFH.write("%s\n" % PML)
257
258
259 def WriteComplexView(OutFH, FileIndex, PyMOLObjectNames):
260 """Write out PML for viewing polymer complex."""
261
262 # Setup complex...
263 Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
264 PML = PyMOLUtil.SetupPMLForPolymerComplexView(PyMOLObjectNames["Complex"], Infile, True)
265 OutFH.write("""\n""\n"Loading %s and setting up view for complex..."\n""\n""" % Infile)
266 OutFH.write("%s\n" % PML)
267
268 if OptionsInfo["SurfaceComplex"]:
269 # Setup hydrophobic surface...
270 PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
271 PyMOLObjectNames["ComplexHydrophobicSurface"],
272 PyMOLObjectNames["Complex"],
273 ColorPalette=OptionsInfo["SurfaceColorPalette"],
274 Enable=False,
275 )
276 OutFH.write("\n%s\n" % PML)
277
278 # Setup complex group...
279 GenerateAndWritePMLForGroup(
280 OutFH, PyMOLObjectNames["ComplexGroup"], PyMOLObjectNames["ComplexGroupMembers"], False, "close"
281 )
282
283
284 def WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
285 """Write out PML for viewing chain."""
286
287 OutFH.write("""\n""\n"Setting up views for chain %s..."\n""\n""" % ChainID)
288
289 ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
290
291 # Setup chain complex group view...
292 WriteChainComplexViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
293
294 # Setup chain view...
295 WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
296
297 # Setup chain solvent view...
298 PML = PyMOLUtil.SetupPMLForSolventView(PyMOLObjectNames["Chains"][ChainID]["Solvent"], ChainComplexName, False)
299 OutFH.write("\n%s\n" % PML)
300
301 # Setup chain inorganic view...
302 PML = PyMOLUtil.SetupPMLForInorganicView(PyMOLObjectNames["Chains"][ChainID]["Inorganic"], ChainComplexName, False)
303 OutFH.write("\n%s\n" % PML)
304
305
306 def WriteChainComplexViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
307 """Write chain complex views."""
308
309 # Setup chain complex...
310 ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
311 PML = PyMOLUtil.SetupPMLForPolymerChainComplexView(ChainComplexName, PyMOLObjectNames["Complex"], ChainID, True)
312 OutFH.write("%s\n" % PML)
313
314 if OptionsInfo["SurfaceChainComplex"]:
315 # Setup hydrophobic surface...
316 PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
317 PyMOLObjectNames["Chains"][ChainID]["ChainComplexHydrophobicSurface"],
318 ChainComplexName,
319 ColorPalette=OptionsInfo["SurfaceColorPalette"],
320 Enable=False,
321 )
322 OutFH.write("\n%s\n" % PML)
323
324 # Setup chain complex group...
325 GenerateAndWritePMLForGroup(
326 OutFH,
327 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"],
328 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"],
329 False,
330 "close",
331 )
332
333
334 def WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
335 """Write individual chain views."""
336
337 ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
338
339 # Setup chain view...
340 ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
341 PML = PyMOLUtil.SetupPMLForPolymerChainView(ChainName, ChainComplexName, True)
342 OutFH.write("\n%s\n" % PML)
343
344 # Setup a non-interface chain view...
345 NonInterfaceChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterface"]
346
347 InterfaceResNums = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["InterfaceResNums"][
348 ChainID
349 ]
350 InterfaceResNumsSelection = "+".join(InterfaceResNums)
351
352 Selection = "%s and chain %s and polymer and (not (resi %s))" % (
353 ChainComplexName,
354 ChainID,
355 InterfaceResNumsSelection,
356 )
357 PML = PyMOLUtil.SetupPMLForSelectionDisplayView(NonInterfaceChainName, Selection, "cartoon", Enable=False)
358 OutFH.write("\n%s\n" % PML)
359
360 if GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
361 # Setup a generic colored surface...
362 PML = PyMOLUtil.SetupPMLForSurfaceView(
363 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurface"],
364 NonInterfaceChainName,
365 Enable=False,
366 Color=OptionsInfo["SurfaceNonInterfaceColor"],
367 )
368 OutFH.write("\n%s\n" % PML)
369
370 if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
371 # Setup surface colored by hydrophobicity...
372 PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
373 PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicSurface"],
374 NonInterfaceChainName,
375 ColorPalette=OptionsInfo["SurfaceColorPalette"],
376 Enable=False,
377 )
378 OutFH.write("\n%s\n" % PML)
379
380 # Setup surface colored by hyrdophobicity and charge...
381 PML = PyMOLUtil.SetupPMLForHydrophobicAndChargeSurfaceView(
382 PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicChargeSurface"],
383 NonInterfaceChainName,
384 OptionsInfo["AtomTypesColorNames"]["HydrophobicAtomsColor"],
385 OptionsInfo["AtomTypesColorNames"]["NegativelyChargedAtomsColor"],
386 OptionsInfo["AtomTypesColorNames"]["PositivelyChargedAtomsColor"],
387 OptionsInfo["AtomTypesColorNames"]["OtherAtomsColor"],
388 Enable=False,
389 DisplayAs=None,
390 )
391 OutFH.write("\n%s\n" % PML)
392
393 if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
394 # Setup electrostatics surface...
395 SelectionObjectName = NonInterfaceChainName
396 ElectrostaticsGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroup"]
397 ElectrostaticsGroupMembers = PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroupMembers"]
398 WriteSurfaceElectrostaticsView(
399 "Chain", OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers
400 )
401
402 # Setup surface group...
403 GenerateAndWritePMLForGroup(
404 OutFH,
405 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroup"],
406 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"],
407 True,
408 "open",
409 )
410
411 # Setup a non-interface group...
412 GenerateAndWritePMLForGroup(
413 OutFH,
414 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroup"],
415 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"],
416 True,
417 "open",
418 )
419
420 # Setup chain group...
421 GenerateAndWritePMLForGroup(
422 OutFH,
423 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"],
424 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"],
425 True,
426 "close",
427 )
428
429
430 def WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID):
431 """Write out PML for viewing ligand in a chain."""
432
433 GroupID = "Ligand"
434 ComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
435
436 # Setup main object...
437 GroupTypeObjectID = "%s" % (GroupID)
438 GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
439
440 OutFH.write("""\n""\n"Setting up views for ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
441 PML = PyMOLUtil.SetupPMLForLigandView(
442 GroupTypeObjectName, ComplexName, LigandID, Enable=True, IgnoreHydrogens=OptionsInfo["IgnoreHydrogens"]
443 )
444 OutFH.write("%s\n" % PML)
445
446 # Setup ball and stick view...
447 BallAndStickNameID = "%sBallAndStick" % (GroupID)
448 BallAndStickName = PyMOLObjectNames["Ligands"][ChainID][LigandID][BallAndStickNameID]
449 PML = PyMOLUtil.SetupPMLForBallAndStickView(BallAndStickName, GroupTypeObjectName, Enable=False)
450 OutFH.write("\n%s\n" % PML)
451
452 # Setup group....
453 GroupNameID = "%sGroup" % (GroupID)
454 GroupMembersID = "%sGroupMembers" % (GroupID)
455 GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
456 GroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID]
457
458 Action = "open"
459 Enable = True
460 GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable, Action)
461
462
463 def WriteInterfacePolarContactsView(OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames):
464 """Write out PML for viewing polar contacts between interface residues."""
465
466 if not OptionsInfo["InterfacePolarContacts"]:
467 return
468
469 WriteInterfaceContactsView(
470 "InterfacePolarConatcts", OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames
471 )
472
473
474 def WriteInterfaceHydrophobicContactsView(OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames):
475 """Write out PML for viewing hydrophobic contacts between interface residues."""
476
477 if not OptionsInfo["InterfaceHydrophobicContacts"]:
478 return
479
480 WriteInterfaceContactsView(
481 "InterfaceHydrophobicContacts", OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames
482 )
483
484
485 def WriteInterfaceContactsView(Mode, OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames):
486 """Write out PML for viewing polar or hydrophobic contacts between interface residues."""
487
488 InterfacePolarContacts = True if re.match("^InterfacePolarConatcts$", Mode, re.I) else False
489
490 ChainIDs1, ChainIDs2 = InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"][InterfaceID]
491 ResNums1, ResNums2 = InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"][InterfaceID]
492
493 FileIndex1, FileIndex2 = InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"][InterfaceID]
494 ComplexName1 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex1]["Complex"]
495 ComplexName2 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex2]["Complex"]
496
497 Selection1 = SetupSelectionForInterfaceContactsView(ComplexName1, ChainIDs1, ResNums1)
498 Selection2 = SetupSelectionForInterfaceContactsView(ComplexName2, ChainIDs2, ResNums2)
499
500 if InterfacePolarContacts:
501 ContactsName = PyMOLObjectNames["InterfaceIDs"][InterfaceID]["PolarContacts"]
502 ContactsColor = OptionsInfo["InterfacePolarContactsColor"]
503 ContactsCutoff = OptionsInfo["InterfaceContactsCutoff"]
504
505 PML = PyMOLUtil.SetupPMLForPolarContactsView(
506 ContactsName, Selection1, Selection2, Enable=False, Color=ContactsColor, Cutoff=ContactsCutoff
507 )
508 else:
509 ContactsName = PyMOLObjectNames["InterfaceIDs"][InterfaceID]["HydrophobicContacts"]
510 ContactsColor = OptionsInfo["InterfaceHydrophobicContactsColor"]
511 ContactsCutoff = OptionsInfo["InterfaceContactsCutoff"]
512
513 PML = PyMOLUtil.SetupPMLForHydrophobicContactsView(
514 ContactsName, Selection1, Selection2, Enable=False, Color=ContactsColor, Cutoff=ContactsCutoff
515 )
516
517 OutFH.write("\n%s\n" % PML)
518
519 OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (ContactsColor, ContactsName))
520
521
522 def SetupSelectionForInterfaceContactsView(ComplexName, ChainIDs, ResNums):
523 """Setup a selection for generating polar or hyrophobic contacts for an interface."""
524
525 ChainSelections = []
526
527 for ChainID in ChainIDs:
528 ChainResNumsSelection = "+".join(ResNums["ResNums"][ChainID])
529 Selection = "(%s and chain %s and polymer and (resi %s))" % (ComplexName, ChainID, ChainResNumsSelection)
530 ChainSelections.append(Selection)
531
532 Selection = " or ".join(ChainSelections)
533
534 return Selection
535
536
537 def WriteInterfaceChainView(
538 OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, ResiduesNums, ComplexName, PyMOLObjectNames
539 ):
540 """Write out PML for viewing interface residues in a chain."""
541
542 OutFH.write("""\n""\n"Setting up interface views for interface in %s..."\n""\n""" % InterfaceChainID)
543
544 ResiduesNumsSelection = "+".join(ResiduesNums)
545
546 # Setup a chain for interface residues...
547 ChainName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["Chain"]
548 Selection = "%s and chain %s and polymer and (resi %s)" % (ComplexName, ChainID, ResiduesNumsSelection)
549
550 PML = PyMOLUtil.SetupPMLForSelectionDisplayView(ChainName, Selection, "lines", Enable=True)
551 OutFH.write("\n%s\n" % PML)
552
553 OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (OptionsInfo["InterfaceLabelColor"], ChainName))
554
555 WriteInterfaceChainResidueTypesView(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLObjectNames)
556
557 if GetInterfaceContainsSurfacesStatus(FileIndex, ChainID):
558 # Setup generic colored surface...
559 PML = PyMOLUtil.SetupPMLForSurfaceView(
560 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurface"],
561 ChainName,
562 Color=OptionsInfo["SurfaceInterfaceColor"],
563 Enable=True,
564 DisplayAs="lines",
565 )
566 OutFH.write("\n%s\n" % PML)
567
568 if GetInterfaceSurfaceChainStatus(FileIndex, ChainID):
569 # Setup surface colored by hydrophobicity...
570 PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
571 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicSurface"],
572 ChainName,
573 ColorPalette=OptionsInfo["SurfaceColorPalette"],
574 Enable=False,
575 DisplayAs="lines",
576 )
577 OutFH.write("\n%s\n" % PML)
578
579 # Setup surface colored by hyrdophobicity and charge...
580 PML = PyMOLUtil.SetupPMLForHydrophobicAndChargeSurfaceView(
581 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicChargeSurface"],
582 ChainName,
583 OptionsInfo["AtomTypesColorNames"]["HydrophobicAtomsColor"],
584 OptionsInfo["AtomTypesColorNames"]["NegativelyChargedAtomsColor"],
585 OptionsInfo["AtomTypesColorNames"]["PositivelyChargedAtomsColor"],
586 OptionsInfo["AtomTypesColorNames"]["OtherAtomsColor"],
587 Enable=False,
588 DisplayAs="lines",
589 )
590 OutFH.write("\n%s\n" % PML)
591
592 if GetInterfaceSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
593 # Setup electrostatics surface...
594 SelectionObjectName = ChainName
595 ElectrostaticsGroupName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][
596 "ChainElectrostaticsGroup"
597 ]
598 ElectrostaticsGroupMembers = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][
599 "ChainElectrostaticsGroupMembers"
600 ]
601 WriteSurfaceElectrostaticsView(
602 "InterfaceResidues", OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers
603 )
604
605 # Setup surface group...
606 GenerateAndWritePMLForGroup(
607 OutFH,
608 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroup"],
609 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"],
610 True,
611 "open",
612 )
613
614 # Setup chain group...
615 GenerateAndWritePMLForGroup(
616 OutFH,
617 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroup"],
618 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"],
619 True,
620 "close",
621 )
622
623
624 def WriteInterfaceChainResidueTypesView(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLObjectNames):
625 """Write out PML for viewing interface residue types for a chain."""
626
627 if not GetInterfaceResidueTypesStatus(FileIndex, ChainID):
628 return
629
630 ChainName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["Chain"]
631
632 # Setup residue types objects...
633 ResiduesGroupIDPrefix = "ChainResidues"
634 for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
635 SubGroupID = re.sub("_", "", SubGroupType)
636
637 ResiduesObjectID = "%s%sResidues" % (ResiduesGroupIDPrefix, SubGroupID)
638 ResiduesObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesObjectID]
639
640 ResiduesSurfaceObjectID = "%s%sSurface" % (ResiduesGroupIDPrefix, SubGroupID)
641 ResiduesSurfaceObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][
642 ResiduesSurfaceObjectID
643 ]
644
645 ResiduesColor = OptionsInfo["ResidueTypesParams"][SubGroupType]["Color"]
646 ResiduesNames = OptionsInfo["ResidueTypesParams"][SubGroupType]["Residues"]
647
648 NegateResidueNames = True if re.match("^Other$", SubGroupType, re.I) else False
649 WriteResidueTypesResiduesAndSurfaceView(
650 OutFH,
651 ChainName,
652 ResiduesObjectName,
653 ResiduesSurfaceObjectName,
654 ResiduesColor,
655 ResiduesNames,
656 NegateResidueNames,
657 )
658
659 # Setup residue type sub groups...
660 ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupIDPrefix, SubGroupID)
661 ResiduesSubGroupMembersID = "%s%sGroupMembers" % (ResiduesGroupIDPrefix, SubGroupID)
662
663 GenerateAndWritePMLForGroup(
664 OutFH,
665 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupID],
666 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupMembersID],
667 True,
668 "close",
669 )
670
671 # Setup residue types group...
672 GenerateAndWritePMLForGroup(
673 OutFH,
674 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainResiduesGroup"],
675 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainResiduesGroupMembers"],
676 False,
677 "close",
678 )
679
680
681 def WriteResidueTypesResiduesAndSurfaceView(
682 OutFH, SelectionObjectName, Name, SurfaceName, ResiduesColor, ResiduesNames, NegateResidueNames
683 ):
684 """Write residue types residues and surface view."""
685
686 ResidueNamesSelection = "+".join(ResiduesNames)
687 if NegateResidueNames:
688 Selection = "%s and (not resn %s)" % (SelectionObjectName, ResidueNamesSelection)
689 else:
690 Selection = "%s and (resn %s)" % (SelectionObjectName, ResidueNamesSelection)
691
692 # Setup residues...
693 PML = PyMOLUtil.SetupPMLForSelectionDisplayView(Name, Selection, "lines", ResiduesColor, True)
694 OutFH.write("\n%s\n" % PML)
695
696 # Setup surface...
697 PML = PyMOLUtil.SetupPMLForSelectionDisplayView(SurfaceName, Selection, "surface", ResiduesColor, True)
698 OutFH.write("\n%s\n" % PML)
699
700
701 def WriteSurfaceElectrostaticsView(
702 Mode, OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers
703 ):
704 """Write out PML for viewing surface electrostatics."""
705
706 if len(ElectrostaticsGroupMembers) == 5:
707 Name, ContactPotentialName, MapName, LegendName, VolumeName = ElectrostaticsGroupMembers
708 else:
709 Name, ContactPotentialName, MapName, LegendName = ElectrostaticsGroupMembers
710 VolumeName = None
711
712 PMLCmds = []
713
714 # Setup chain...
715 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, SelectionObjectName))
716
717 # Setup vacuum electrostatics surface along with associated objects...
718 PMLCmds.append("""util.protein_vacuum_esp("%s", mode=2, quiet=0, _self=cmd)""" % (Name))
719
720 PMLCmds.append("""cmd.set_name("%s_e_chg", "%s")""" % (Name, ContactPotentialName))
721 if re.match("^Chain$", Mode, re.I):
722 DisplayStyle = "cartoon"
723 else:
724 DisplayStyle = "lines"
725 PMLCmds.append("""cmd.show("%s", "(%s)")""" % (DisplayStyle, ContactPotentialName))
726 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(ContactPotentialName, Enable=True))
727
728 PMLCmds.append("""cmd.set_name("%s_e_map", "%s")""" % (Name, MapName))
729 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MapName, Enable=False))
730
731 PMLCmds.append("""cmd.set_name("%s_e_pot", "%s")""" % (Name, LegendName))
732 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(LegendName, Enable=False))
733
734 if VolumeName is not None:
735 PMLCmds.append("""cmd.volume("%s", "%s", "%s", "(%s)")""" % (VolumeName, MapName, "esp", Name))
736 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(VolumeName, Enable=False))
737
738 # Delete name and take it out from the group membership. It is
739 # is already part of ContactPotential object.
740 PMLCmds.append("""cmd.delete("%s")""" % (Name))
741 ElectrostaticsGroupMembers.pop(0)
742
743 PML = "\n".join(PMLCmds)
744
745 OutFH.write("\n%s\n" % PML)
746
747 # Setup group...
748 GenerateAndWritePMLForGroup(OutFH, ElectrostaticsGroupName, ElectrostaticsGroupMembers, False, "close")
749
750
751 def GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable=False, Action="close"):
752 """Generate and write PML for group."""
753
754 PML = PyMOLUtil.SetupPMLForGroup(GroupName, GroupMembers, Enable, Action)
755 OutFH.write("""\n""\n"Setting up group %s..."\n""\n""" % GroupName)
756 OutFH.write("%s\n" % PML)
757
758
759 def GeneratePyMOLSessionFile():
760 """Generate PME file from PML file."""
761
762 PSEOutfile = OptionsInfo["PSEOutfile"]
763 PMLOutfile = OptionsInfo["PMLOutfile"]
764
765 MiscUtil.PrintInfo("\nGenerating file %s..." % PSEOutfile)
766
767 PyMOLUtil.ConvertPMLFileToPSEFile(PMLOutfile, PSEOutfile)
768
769 if not os.path.exists(PSEOutfile):
770 MiscUtil.PrintWarning("Failed to generate PSE file, %s..." % (PSEOutfile))
771
772 if not OptionsInfo["PMLOut"]:
773 MiscUtil.PrintInfo("Deleting file %s..." % PMLOutfile)
774 os.remove(PMLOutfile)
775
776
777 def DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames):
778 """Delete empty PyMOL objects."""
779
780 if OptionsInfo["AllowEmptyObjects"]:
781 return
782
783 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
784 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
785 OutFH.write("""\n""\n"Checking and deleting empty objects for chain %s..."\n""\n""" % (ChainID))
786
787 # Delete any chain level objects...
788 WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Solvent"])
789 WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Inorganic"])
790
791
792 def DeleteEmptyPyMOLInterfaceObjects(OutFH):
793 """Delete empty PyMOL interface objects."""
794
795 if OptionsInfo["AllowEmptyObjects"]:
796 return
797
798 InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
799 PyMOLInterfaceObjectNamesInfo = OptionsInfo["InfilesInfo"]["PyMOLInterfaceObjectNamesInfo"]
800
801 if InterfaceChainsAndResiduesInfo is None:
802 return
803
804 for InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
805 for InterfaceChainID in InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID]:
806 ChainID = InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID]
807 FileIndex = InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID]
808
809 # Delete interface residue type objects...
810 DeleteEmptyInterfaceChainResidueTypesObjects(
811 OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLInterfaceObjectNamesInfo
812 )
813
814
815 def DeleteEmptyInterfaceChainResidueTypesObjects(
816 OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLObjectNames
817 ):
818 """Delete empty interface chain residue objects."""
819
820 if not GetInterfaceResidueTypesStatus(FileIndex, ChainID):
821 return
822
823 ResiduesGroupIDPrefix = "ChainResidues"
824 for GroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
825 GroupID = re.sub("_", "", GroupType)
826
827 ResiduesGroupID = "%s%sGroup" % (ResiduesGroupIDPrefix, GroupID)
828 GroupName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupID]
829
830 GroupObjectNamesList = []
831
832 ResiduesObjectID = "%s%sResidues" % (ResiduesGroupIDPrefix, GroupID)
833 ResiduesObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesObjectID]
834 GroupObjectNamesList.append(ResiduesObjectName)
835
836 ResiduesSurfaceObjectID = "%s%sSurface" % (ResiduesGroupIDPrefix, GroupID)
837 ResiduesSurfaceObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][
838 ResiduesSurfaceObjectID
839 ]
840 GroupObjectNamesList.append(ResiduesSurfaceObjectName)
841
842 GroupObjectNames = ",".join(GroupObjectNamesList)
843 WritePMLToCheckAndDeleteEmptyObjects(OutFH, GroupObjectNames, GroupName)
844
845
846 def WritePMLToCheckAndDeleteEmptyObjects(OutFH, ObjectName, ParentObjectName=None):
847 """Write PML to check and delete empty PyMOL objects."""
848
849 if ParentObjectName is None:
850 PML = """CheckAndDeleteEmptyObjects("%s")""" % (ObjectName)
851 else:
852 PML = """CheckAndDeleteEmptyObjects("%s", "%s")""" % (ObjectName, ParentObjectName)
853
854 OutFH.write("%s\n" % PML)
855
856
857 def RetrieveInfilesInfo():
858 """Retrieve information for input files."""
859
860 InfilesInfo = {}
861
862 InfilesInfo["InfilesNames"] = []
863 InfilesInfo["InfilesRoots"] = []
864 InfilesInfo["ChainsAndLigandsInfo"] = []
865 InfilesInfo["SpecifiedChainsAndLigandsInfo"] = []
866
867 InfilesInfo["PyMOLObjectNamesInfo"] = []
868
869 InfilesInfo["SingleInfileMode"] = False
870 InfilesInfo["InterfaceChainsAndResiduesInfo"] = None
871 InfilesInfo["InterfaceChainPairsAndResiduesInfo"] = None
872
873 InfilesInfo["PyMOLInterfaceObjectNamesInfo"] = None
874
875 InfilesCount = 0
876 for Infile in OptionsInfo["InfilesNames"]:
877 InfilesCount += 1
878 FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
879 InfileRoot = FileName
880
881 ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(Infile, InfileRoot)
882
883 InfilesInfo["InfilesNames"].append(Infile)
884 InfilesInfo["InfilesRoots"].append(InfileRoot)
885 InfilesInfo["ChainsAndLigandsInfo"].append(ChainsAndLigandInfo)
886
887 if InfilesCount > 2:
888 MiscUtil.PrintError(
889 'Number of input files, %s, specified using "-i, --infiles" option is not valid. Number of allowed files: 1 or 2'
890 % (InfilesCount)
891 )
892
893 InfilesInfo["SingleInfileMode"] = True if InfilesCount == 1 else False
894
895 OptionsInfo["InfilesInfo"] = InfilesInfo
896
897
898 def ProcessInterfaceChainIDs():
899 """Process specified interface chain IDs for input files."""
900
901 ValidateInterfaceChainIDs()
902
903 SetupChainsAndLigandsInfo()
904 SetupPyMOLObjectNamesInfo()
905
906 SetupInterfaceChainPairsAndResiduesInfo()
907 ProcessInterfaceChainPairsAndResiduesInfo()
908
909 SetupPyMOLInterfaceObjectNamesInfo()
910
911
912 def ValidateInterfaceChainIDs():
913 """Check for the presence of interface IDs in input file(s)."""
914
915 if re.match("^auto$", OptionsInfo["InterfaceChainIDs"], re.I):
916 AutoAssignInterfaceChainIDs()
917 SetupInfilesInterfaceChainIDsLists()
918 return
919
920 MiscUtil.PrintInfo("\nValidating interface chain IDs...")
921
922 # Check for the presences of interface chain IDs across input files..
923 SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
924 Infile1ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]["ChainIDs"]
925 Infile2ChainIDs = []
926 if not SingleInfileMode:
927 Infile2ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][1]["ChainIDs"]
928
929 InterfaceChainIDsList = OptionsInfo["InterfaceChainIDsList"]
930
931 for Index in range(0, len(InterfaceChainIDsList), 2):
932 ChainIDs1 = InterfaceChainIDsList[Index]
933 ChainIDs2 = InterfaceChainIDsList[Index + 1]
934
935 for ChainID in ChainIDs1:
936 if ChainID not in Infile1ChainIDs:
937 MiscUtil.PrintError(
938 'The chain ID, %s, specified using "-c, --chainIDs" for a chain IDs pairs, "%s,%s", must be present in first input file.'
939 % (ChainID, "+".join(ChainIDs1), "+".join(ChainIDs2))
940 )
941
942 for ChainID in ChainIDs2:
943 if SingleInfileMode:
944 if ChainID not in Infile1ChainIDs:
945 MiscUtil.PrintError(
946 'The chain ID, %s, specified using "-c, --chainIDs" for a chain IDs pairs, "%s,%s", must be present in first input file.'
947 % (ChainID, "+".join(ChainIDs1), "+".join(ChainIDs2))
948 )
949 else:
950 if ChainID not in Infile2ChainIDs:
951 MiscUtil.PrintError(
952 'The chain ID, %s, specified using "-c, --chainIDs" for a chain IDs pairs, "%s,%s", must be present in second input file.'
953 % (ChainID, "+".join(ChainIDs1), "+".join(ChainIDs2))
954 )
955
956 # Check for any duplicate interface chain IDs specifications...
957 CanonicalInterfaceIDsMap = {}
958
959 for Index in range(0, len(InterfaceChainIDsList), 2):
960 ChainIDs1 = InterfaceChainIDsList[Index]
961 ChainIDs2 = InterfaceChainIDsList[Index + 1]
962 InterfaceID = "%s,%s" % ("+".join(ChainIDs1), "+".join(ChainIDs2))
963
964 SortedChainIDs1 = sorted(ChainIDs1)
965 SortedChainIDs2 = sorted(ChainIDs2)
966 CanonicalInterfaceID = "%s,%s" % ("+".join(SortedChainIDs1), "+".join(SortedChainIDs2))
967
968 if CanonicalInterfaceID in CanonicalInterfaceIDsMap:
969 MiscUtil.PrintError(
970 'The chain ID pair, "%s", using "-c, --chainIDs", option has been specified multiple times, "%s".'
971 % (CanonicalInterfaceIDsMap[CanonicalInterfaceID], OptionsInfo["InterfaceChainIDs"])
972 )
973 else:
974 CanonicalInterfaceIDsMap[CanonicalInterfaceID] = InterfaceID
975
976 SetupInfilesInterfaceChainIDsLists()
977
978
979 def SetupInfilesInterfaceChainIDsLists():
980 """Setup interface chain IDs list for infiles."""
981
982 Infie1InterfaceChainIDsList = []
983 Infie2InterfaceChainIDsList = []
984
985 SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
986 InterfaceChainIDsList = OptionsInfo["InterfaceChainIDsList"]
987
988 for Index in range(0, len(InterfaceChainIDsList), 2):
989 ChainIDs1 = InterfaceChainIDsList[Index]
990 ChainIDs2 = InterfaceChainIDsList[Index + 1]
991
992 Infie1InterfaceChainIDsList.extend(ChainIDs1)
993 if SingleInfileMode:
994 Infie1InterfaceChainIDsList.extend(ChainIDs2)
995 else:
996 Infie2InterfaceChainIDsList.extend(ChainIDs2)
997
998 Infie1InterfaceChainIDsList = sorted(Infie1InterfaceChainIDsList)
999 Infie2InterfaceChainIDsList = sorted(Infie2InterfaceChainIDsList)
1000
1001 OptionsInfo["InfilesInterfaceChainIDsList"] = [Infie1InterfaceChainIDsList, Infie2InterfaceChainIDsList]
1002
1003
1004 def AutoAssignInterfaceChainIDs():
1005 """Handle automatic assignment of interface chain IDs."""
1006
1007 Infile1ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]["ChainIDs"]
1008 Infile2ChainIDs = []
1009 if not OptionsInfo["InfilesInfo"]["SingleInfileMode"]:
1010 Infile2ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][1]["ChainIDs"]
1011
1012 InterfaceChainIDsList = []
1013 if OptionsInfo["InfilesInfo"]["SingleInfileMode"]:
1014 # Take first two chains from first input file...
1015 if len(Infile1ChainIDs) < 2:
1016 MiscUtil.PrintError(
1017 'Failed to automatically set interface chain IDs. Number of chains, %s, in input file specified using "-i, --infiles" option must be >= 2. '
1018 % (len(Infile1ChainIDs))
1019 )
1020 InterfaceChainIDsList.append([Infile1ChainIDs[0]])
1021 InterfaceChainIDsList.append([Infile1ChainIDs[1]])
1022 else:
1023 # Take first chain from each input file...
1024 if len(Infile1ChainIDs) < 1:
1025 MiscUtil.PrintError(
1026 'Failed to automatically set interface chain IDs. Number of chains, %s, in first input file specified using "-i, --infiles" option must be >= 1. '
1027 % (len(Infile1ChainIDs))
1028 )
1029 if len(Infile2ChainIDs) < 1:
1030 MiscUtil.PrintError(
1031 'Failed to automatically set interface chain IDs. Number of chains, %s, in second input file specified using "-i, --infiles" option must be >= 1. '
1032 % (len(Infile1ChainIDs))
1033 )
1034 InterfaceChainIDsList.append([Infile1ChainIDs[0]])
1035 InterfaceChainIDsList.append([Infile2ChainIDs[1]])
1036
1037 OptionsInfo["InterfaceChainIDsList"] = []
1038 OptionsInfo["InterfaceChainIDsList"].extend(InterfaceChainIDsList)
1039
1040 return
1041
1042
1043 def SetupChainsAndLigandsInfo():
1044 """Setup chains and ligands info for input files to visualize macromolecules."""
1045
1046 OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"] = []
1047 for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
1048 Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
1049 MiscUtil.PrintInfo("\nSetting up chain and ligand information for input file %s..." % Infile)
1050
1051 ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
1052 InfilesInterfaceChainIDsList = OptionsInfo["InfilesInterfaceChainIDsList"][FileIndex]
1053
1054 SpecifiedChainsAndLigandsInfo = {}
1055 SpecifiedChainsAndLigandsInfo["ChainIDs"] = []
1056 SpecifiedChainsAndLigandsInfo["InterfaceResNums"] = {}
1057 SpecifiedChainsAndLigandsInfo["LigandIDs"] = {}
1058
1059 if len(InfilesInterfaceChainIDsList):
1060 # Add unique interface IDs to the chain IDs list for visualization. Interface chain IDs
1061 # may contain duplicate chain IDs due to the presence # of same chain in multiple
1062 # interfaces.
1063 for ChainID in InfilesInterfaceChainIDsList:
1064 if ChainID not in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1065 SpecifiedChainsAndLigandsInfo["ChainIDs"].append(ChainID)
1066
1067 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1068 # Initialize interface residue numbers to be assigned later...
1069 SpecifiedChainsAndLigandsInfo["InterfaceResNums"][ChainID] = []
1070
1071 # Setup ligand IDs...
1072 SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID] = SetupSpecifiedLigandIDs(
1073 FileIndex, ChainID, ChainsAndLigandsInfo
1074 )
1075
1076 ProcessResidueTypesAndSurfaceOptions(FileIndex, SpecifiedChainsAndLigandsInfo)
1077
1078 OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"].append(SpecifiedChainsAndLigandsInfo)
1079
1080
1081 def SetupSpecifiedLigandIDs(FileIndex, ChainID, ChainsAndLigandsInfo):
1082 """Setup specified ligand IDs for input file."""
1083
1084 LigandIDs = []
1085
1086 if re.match("^All$", OptionsInfo["LigandIDs"], re.I):
1087 LigandIDs = ChainsAndLigandsInfo["LigandIDs"][ChainID]
1088 return LigandIDs
1089 elif re.match("^Largest|Auto$", OptionsInfo["LigandIDs"], re.I):
1090 LargestLigandID = (
1091 ChainsAndLigandsInfo["LigandIDs"][ChainID][0] if (len(ChainsAndLigandsInfo["LigandIDs"][ChainID])) else None
1092 )
1093 if LargestLigandID is not None:
1094 LigandIDs.append(LargestLigandID)
1095 return LigandIDs
1096 elif re.match("^None$", OptionsInfo["LigandIDs"], re.I):
1097 return LigandIDs
1098
1099 Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
1100 ValidLigandIDs = ChainsAndLigandsInfo["LigandIDs"][ChainID]
1101
1102 SpecifiedLigandIDs = re.sub(" ", "", OptionsInfo["LigandIDs"])
1103 if not SpecifiedLigandIDs:
1104 MiscUtil.PrintError('No valid value specified using "-l, --ligandIDs" option.')
1105
1106 LigandIDsWords = SpecifiedLigandIDs.split(",")
1107 for LigandID in LigandIDsWords:
1108 if LigandID not in ValidLigandIDs:
1109 LigandIDsListNames = ",".join(ValidLigandIDs) if len(ValidLigandIDs) else "None"
1110 MiscUtil.PrintWarning(
1111 'The ligand ID, %s, specified using "-l, --ligandiIDs" option is not valid for chain, %s, in input file, %s. It\'ll be ignored. Valid ligand IDs: %s'
1112 % (LigandID, ChainID, Infile, LigandIDsListNames)
1113 )
1114 continue
1115
1116 if LigandID in LigandIDs:
1117 MiscUtil.PrintWarning(
1118 'The ligand ID, %s, has already been specified using "-l, --ligandIDs" option for chain, %s, in input file, %s. It\'ll be ignored.'
1119 % (LigandID, ChainID, Infile)
1120 )
1121 continue
1122
1123 LigandIDs.append(LigandID)
1124
1125 if not len(LigandIDs):
1126 MiscUtil.PrintWarning(
1127 'No valid ligand IDs "%s" specified using "-l, --ligandIDs" option for chain ID, %s, in input file, %s.'
1128 % (OptionsInfo["LigandIDs"], ChainID, Infile)
1129 )
1130
1131 return LigandIDs
1132
1133
1134 def SetupInterfaceChainPairsAndResiduesInfo():
1135 """Setup chain and residue pairs corresponding to interfaces."""
1136
1137 MiscUtil.PrintInfo("\nIdentifying interface residues...")
1138
1139 SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
1140 InterfaceChainIDsList = OptionsInfo["InterfaceChainIDsList"]
1141
1142 if not len(InterfaceChainIDsList):
1143 MiscUtil.PrintError("Failed to identify interface residues: No valid chain ID pairs available for interfaces")
1144
1145 # Load infiles to identify interface residues...
1146 Infile1 = OptionsInfo["InfilesInfo"]["InfilesNames"][0]
1147 MolName1 = OptionsInfo["InfilesInfo"]["InfilesRoots"][0]
1148 pymol.cmd.load(Infile1, MolName1)
1149 if SingleInfileMode:
1150 MolName2 = MolName1
1151 else:
1152 Infile2 = OptionsInfo["InfilesInfo"]["InfilesNames"][1]
1153 MolName2 = OptionsInfo["InfilesInfo"]["InfilesRoots"][1]
1154 pymol.cmd.load(Infile2, MolName2)
1155
1156 # Initialize data...
1157 InterfaceChainPairsAndResiduesInfo = {}
1158 InterfaceChainPairsAndResiduesInfo["InterfaceIDs"] = []
1159 InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"] = {}
1160 InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"] = {}
1161 InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"] = {}
1162
1163 Method = OptionsInfo["Method"]
1164 MethodCutoff = OptionsInfo["MethodCutoff"]
1165 MiscUtil.PrintInfo("Methodology: %s; Cutoff: %.2f" % (Method, MethodCutoff))
1166
1167 for Index in range(0, len(InterfaceChainIDsList), 2):
1168 ChainIDs1 = sorted(InterfaceChainIDsList[Index])
1169 ChainIDs2 = sorted(InterfaceChainIDsList[Index + 1])
1170
1171 ChainIDs1Prefix = "Chains" if len(ChainIDs1) > 1 else "Chain"
1172 ChainIDs2Prefix = "Chains" if len(ChainIDs2) > 1 else "Chain"
1173 InterfaceID = "%s%s_%s%s" % (ChainIDs1Prefix, "+".join(ChainIDs1), ChainIDs2Prefix, "+".join(ChainIDs2))
1174
1175 ListInterfaceID = "%s_%s" % ("+".join(ChainIDs1), "+".join(ChainIDs2))
1176
1177 FileIndex1 = 0
1178 FileIndex2 = 0 if SingleInfileMode else 1
1179
1180 if InterfaceID in InterfaceChainPairsAndResiduesInfo["InterfaceIDs"]:
1181 MiscUtil.PrintInfo("Ignoring interface ID %s: It has already been defined" % InterfaceID)
1182 continue
1183
1184 # Identify and list interface chains and residues...
1185 ChainsAndResiduesInfo1, ChainsAndResiduesInfo2 = GetInterfaceChainsAndResiduesInfo(
1186 MolName1, ChainIDs1, MolName2, ChainIDs2, Method, MethodCutoff
1187 )
1188 ListInterfaceChainsAndResidues(
1189 ListInterfaceID, MolName1, ChainIDs1, ChainsAndResiduesInfo1, MolName2, ChainIDs2, ChainsAndResiduesInfo2
1190 )
1191
1192 # Check presence of interface residues...
1193 if not (len(ChainsAndResiduesInfo1["ChainIDs"]) and len(ChainsAndResiduesInfo2["ChainIDs"])):
1194 MiscUtil.PrintWarning(
1195 "Ignoring interface ID %s: Failed to identify any interface residues. PyMOL groups and objects won't be created."
1196 % InterfaceID
1197 )
1198 continue
1199
1200 # Collect residue numbers for set of interface residues in each chain...
1201 InterfaceChainIDs1, InterfaceChainResidueNums1 = GetInterfaceChainsAndResidueNumbers(
1202 ChainIDs1, ChainsAndResiduesInfo1
1203 )
1204 InterfaceChainIDs2, InterfaceChainResidueNums2 = GetInterfaceChainsAndResidueNumbers(
1205 ChainIDs2, ChainsAndResiduesInfo2
1206 )
1207
1208 InterfaceChainPairsAndResiduesInfo["InterfaceIDs"].append(InterfaceID)
1209 InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"][InterfaceID] = [InterfaceChainIDs1, InterfaceChainIDs2]
1210 InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"][InterfaceID] = [
1211 InterfaceChainResidueNums1,
1212 InterfaceChainResidueNums2,
1213 ]
1214 InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"][InterfaceID] = [FileIndex1, FileIndex2]
1215
1216 InterfaceChainPairsAndResiduesInfo["InterfaceIDs"] = sorted(InterfaceChainPairsAndResiduesInfo["InterfaceIDs"])
1217 OptionsInfo["InfilesInfo"]["InterfaceChainPairsAndResiduesInfo"] = InterfaceChainPairsAndResiduesInfo
1218
1219 # Delete loaded objects...
1220 pymol.cmd.delete(MolName1)
1221 if not SingleInfileMode:
1222 pymol.cmd.delete(MolName2)
1223
1224
1225 def ProcessInterfaceChainPairsAndResiduesInfo():
1226 """Process chain and residue pairs for visualizing interfaces."""
1227
1228 InterfaceChainsAndResiduesInfo = {}
1229 InterfaceChainsAndResiduesInfo["InterfaceIDs"] = []
1230 InterfaceChainsAndResiduesInfo["InterfaceChainIDs"] = {}
1231 InterfaceChainsAndResiduesInfo["ChainIDs"] = {}
1232 InterfaceChainsAndResiduesInfo["ChainIDsResNums"] = {}
1233 InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"] = {}
1234 InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"] = {}
1235
1236 InterfaceChainPairsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainPairsAndResiduesInfo"]
1237
1238 for InterfaceID in InterfaceChainPairsAndResiduesInfo["InterfaceIDs"]:
1239 # Flatten pairwise interface chain and residues info...
1240 (
1241 FlattenedInterfaceChainIDs,
1242 FlattenedChainIDs,
1243 FlattenedResNums,
1244 FlattenedComplexNames,
1245 FlattenedInfileIndices,
1246 ) = FlattenIntferfaceChainPairsAndResiduesInfo(InterfaceChainPairsAndResiduesInfo, InterfaceID)
1247
1248 if InterfaceID not in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
1249 InterfaceChainsAndResiduesInfo["InterfaceIDs"].append(InterfaceID)
1250
1251 InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID] = []
1252 InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID] = {}
1253 InterfaceChainsAndResiduesInfo["ChainIDsResNums"][InterfaceID] = {}
1254 InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"][InterfaceID] = {}
1255 InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID] = {}
1256
1257 # Track interface information for visualization...
1258 for Index in range(0, len(FlattenedInterfaceChainIDs)):
1259 InterfaceChainID = FlattenedInterfaceChainIDs[Index]
1260 ChainID = FlattenedChainIDs[Index]
1261 ResNums = FlattenedResNums[Index]
1262 ComplexName = FlattenedComplexNames[Index]
1263 FileIndex = FlattenedInfileIndices[Index]
1264
1265 if not len(ResNums):
1266 continue
1267
1268 InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID].append(InterfaceChainID)
1269 InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID] = ChainID
1270 InterfaceChainsAndResiduesInfo["ChainIDsResNums"][InterfaceID][InterfaceChainID] = ResNums
1271 InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"][InterfaceID][InterfaceChainID] = ComplexName
1272 InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID] = FileIndex
1273
1274 OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["InterfaceResNums"][ChainID].extend(
1275 ResNums
1276 )
1277
1278 OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"] = InterfaceChainsAndResiduesInfo
1279
1280
1281 def FlattenIntferfaceChainPairsAndResiduesInfo(InterfaceChainPairsAndResiduesInfo, InterfaceID):
1282 """Flatten interface chain and residues info."""
1283
1284 SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
1285
1286 ChainIDs1, ChainIDs2 = InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"][InterfaceID]
1287 ResNums1, ResNums2 = InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"][InterfaceID]
1288 FileIndex1, FileIndex2 = InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"][InterfaceID]
1289
1290 # Set complex names..
1291 PDBGroup1 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex1]["PDBGroup"]
1292 ComplexName1 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex1]["Complex"]
1293
1294 PDBGroup2 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex2]["PDBGroup"]
1295 ComplexName2 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex2]["Complex"]
1296
1297 ChainIDs = []
1298 InterfaceChainIDs = []
1299 ResNums = []
1300 ComplexNames = []
1301 FileIndices = []
1302
1303 for ChainID in ChainIDs1:
1304 ChainIDs.append(ChainID)
1305 InterfaceChainID = ("Chain%s" % ChainID) if SingleInfileMode else ("Chain%s_%s" % (ChainID, PDBGroup1))
1306 InterfaceChainIDs.append(InterfaceChainID)
1307 ResNums.append(ResNums1["ResNums"][ChainID])
1308 ComplexNames.append(ComplexName1)
1309 FileIndices.append(FileIndex1)
1310
1311 for ChainID in ChainIDs2:
1312 ChainIDs.append(ChainID)
1313 InterfaceChainID = ("Chain%s" % ChainID) if SingleInfileMode else ("Chain%s_%s" % (ChainID, PDBGroup2))
1314 InterfaceChainIDs.append(InterfaceChainID)
1315 ResNums.append(ResNums2["ResNums"][ChainID])
1316 ComplexNames.append(ComplexName2)
1317 FileIndices.append(FileIndex2)
1318
1319 return InterfaceChainIDs, ChainIDs, ResNums, ComplexNames, FileIndices
1320
1321
1322 def GetInterfaceChainsAndResiduesInfo(MolName1, ChainIDs1, MolName2, ChainIDs2, Method, Cutoff):
1323 """Get interface chains and residues info for chains using a specified methodology."""
1324
1325 InterfaceChainsResiduesInfo1 = None
1326 InterfaceChainsResiduesInfo2 = None
1327
1328 ChainNames1 = ",".join(ChainIDs1)
1329 ChainNames2 = ",".join(ChainIDs2)
1330
1331 if re.match("^BySASAChange$", Method, re.I):
1332 InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2 = PyMOLUtil.GetInterfaceChainsResiduesBySASAChange(
1333 MolName1, ChainNames1, MolName2, ChainNames2, Cutoff
1334 )
1335 elif re.match("^ByHeavyAtomsDistance$", Method, re.I):
1336 InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2 = (
1337 PyMOLUtil.GetInterfaceChainsResiduesByHeavyAtomsDistance(
1338 MolName1, ChainNames1, MolName2, ChainNames2, Cutoff
1339 )
1340 )
1341 elif re.match("^ByCAlphaAtomsDistance$", Method, re.I):
1342 InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2 = (
1343 PyMOLUtil.GetInterfaceChainsResiduesByCAlphaAtomsDistance(
1344 MolName1, ChainNames1, MolName2, ChainNames2, Cutoff
1345 )
1346 )
1347 else:
1348 MiscUtil.PrintError("Failed to retrieve interface residues information: Method %s is not valid..." % Method)
1349
1350 return InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2
1351
1352
1353 def ListInterfaceChainsAndResidues(
1354 InterfaceID, MolName1, ChainIDs1, ChainsAndResiduesInfo1, MolName2, ChainIDs2, ChainsAndResiduesInfo2
1355 ):
1356 """List interface chains and residues for an interface."""
1357
1358 ChainNames1, ResiduesInfo1 = PrepareInterfaceChainsAndResiduesInfo(ChainsAndResiduesInfo1)
1359 ChainNames2, ResiduesInfo2 = PrepareInterfaceChainsAndResiduesInfo(ChainsAndResiduesInfo2)
1360
1361 if len(ChainNames1) and len(ChainNames2):
1362 MiscUtil.PrintInfo("\nListing interface residues for interface chain IDs: %s" % (InterfaceID))
1363
1364 ListInterfaceChainsAndResiduesInfo(InterfaceID, MolName1, ChainIDs1, ChainNames1, ResiduesInfo1)
1365 ListInterfaceChainsAndResiduesInfo(InterfaceID, MolName2, ChainIDs2, ChainNames2, ResiduesInfo2)
1366 else:
1367 MiscUtil.PrintInfo("\nListing interface residues for interface chain IDs: %s" % (InterfaceID))
1368 MiscUtil.PrintInfo("Interface chain IDs: None; ChainID: None; Number of interface residues: 0")
1369
1370
1371 def PrepareInterfaceChainsAndResiduesInfo(ChainsAndResiduesInfo):
1372 """Prepare interface chains and residues info for listing."""
1373
1374 ChainNames = []
1375 ResiduesInfo = []
1376
1377 for ChainID in ChainsAndResiduesInfo["ChainIDs"]:
1378 ChainNames.append(ChainID)
1379
1380 # Setup distribution of residues...
1381 LineWords = []
1382 ResiduesCount = 0
1383 SortedResNames = sorted(
1384 ChainsAndResiduesInfo["ResNames"][ChainID],
1385 key=lambda ResName: ChainsAndResiduesInfo["ResCount"][ChainID][ResName],
1386 reverse=True,
1387 )
1388 for ResName in SortedResNames:
1389 ResCount = ChainsAndResiduesInfo["ResCount"][ChainID][ResName]
1390 LineWords.append("%s - %s" % (ResName, ResCount))
1391 ResiduesCount += ResCount
1392
1393 ResiduesDistribution = "; ".join(LineWords) if len(LineWords) else None
1394
1395 # Setup residue IDs sorted by residue numbers...
1396 ResNumMap = {}
1397 for ResName in ChainsAndResiduesInfo["ResNames"][ChainID]:
1398 for ResNum in ChainsAndResiduesInfo["ResNum"][ChainID][ResName]:
1399 ResNumMap[ResNum] = ResName
1400
1401 LineWords = []
1402 for ResNum in sorted(ResNumMap, key=int):
1403 ResName = ResNumMap[ResNum]
1404 ResID = "%s_%s" % (ResName, ResNum)
1405 LineWords.append(ResID)
1406 ResiduesIDs = ", ".join(LineWords) if len(LineWords) else None
1407
1408 ResiduesInfo.append([ResiduesCount, ResiduesDistribution, ResiduesIDs])
1409
1410 return ChainNames, ResiduesInfo
1411
1412
1413 def ListInterfaceChainsAndResiduesInfo(InterfaceID, MolName, InterfaceChainIDs, ChainNames, ResiduesInfo):
1414 """List interface chains and residues."""
1415
1416 for ChainID in InterfaceChainIDs:
1417 if ChainID not in ChainNames:
1418 MiscUtil.PrintWarning(
1419 "Interface chain IDs: %s; MoleculeID: %s; ChainID: %s; Number of interface residues: 0. PyMOL groups and objects related to chain won't be created."
1420 % (InterfaceID, MolName, ChainID)
1421 )
1422 continue
1423
1424 for Index in range(0, len(ChainNames)):
1425 ChainName = ChainNames[Index]
1426 ChainResiduesInfo = ResiduesInfo[Index]
1427 if re.match(ChainID, ChainName, re.I):
1428 MiscUtil.PrintInfo(
1429 "\nInterface chain IDs: %s; MoleculeID: %s; ChainID: %s; Number of interface residues: %d"
1430 % (InterfaceID, MolName, ChainName, ChainResiduesInfo[0])
1431 )
1432 MiscUtil.PrintInfo(
1433 "Residue distribution: %s\nResidue IDs: %s" % (ChainResiduesInfo[1], ChainResiduesInfo[2])
1434 )
1435 continue
1436
1437
1438 def GetInterfaceChainsAndResidueNumbers(ChainIDs, ChainsAndResiduesInfo):
1439 """Collect interface residue numbers for chains."""
1440
1441 ChainResidueNums = {}
1442 ChainResidueNums["ChainIDs"] = []
1443 ChainResidueNums["ResNums"] = {}
1444
1445 for ChainID in ChainIDs:
1446 if ChainID not in ChainsAndResiduesInfo["ChainIDs"]:
1447 continue
1448
1449 ChainResidueNums["ChainIDs"].append(ChainID)
1450 ChainResidueNums["ResNums"][ChainID] = []
1451
1452 ResNums = []
1453 for ResName in ChainsAndResiduesInfo["ResNames"][ChainID]:
1454 ResNums.extend(ChainsAndResiduesInfo["ResNum"][ChainID][ResName])
1455
1456 ChainResidueNums["ResNums"][ChainID] = sorted(ResNums, key=int)
1457
1458 InterfaceChainIDs = ChainResidueNums["ChainIDs"]
1459
1460 return InterfaceChainIDs, ChainResidueNums
1461
1462
1463 def SetupPyMOLObjectNamesInfo():
1464 """Setup PyMOL object names for displaying macromolecules."""
1465
1466 OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"] = []
1467
1468 for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
1469 PyMOLObjectNamesInfo = SetupPyMOLObjectNames(FileIndex)
1470 OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"].append(PyMOLObjectNamesInfo)
1471
1472
1473 def SetupPyMOLObjectNames(FileIndex):
1474 """Setup hierarchy of PyMOL groups and objects for ligand centric views of
1475 chains and ligands present in input file.
1476 """
1477
1478 PyMOLObjectNames = {}
1479 PyMOLObjectNames["Chains"] = {}
1480 PyMOLObjectNames["Ligands"] = {}
1481
1482 # Setup groups and objects for complex...
1483 SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames)
1484
1485 # Setup groups and objects for chain...
1486 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
1487 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1488 SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID)
1489
1490 # Setup groups and objects for ligand...
1491 for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
1492 SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID)
1493
1494 return PyMOLObjectNames
1495
1496
1497 def SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames):
1498 """Setup groups and objects for complex."""
1499
1500 PDBFileRoot = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
1501
1502 PDBGroupName = "%s" % PDBFileRoot
1503 PyMOLObjectNames["PDBGroup"] = PDBGroupName
1504 PyMOLObjectNames["PDBGroupMembers"] = []
1505
1506 ComplexGroupName = "%s.Complex" % PyMOLObjectNames["PDBGroup"]
1507 PyMOLObjectNames["ComplexGroup"] = ComplexGroupName
1508 PyMOLObjectNames["PDBGroupMembers"].append(ComplexGroupName)
1509
1510 PyMOLObjectNames["Complex"] = "%s.Complex" % ComplexGroupName
1511 if OptionsInfo["SurfaceComplex"]:
1512 PyMOLObjectNames["ComplexHydrophobicSurface"] = "%s.Surface" % ComplexGroupName
1513
1514 PyMOLObjectNames["ComplexGroupMembers"] = []
1515 PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["Complex"])
1516 if OptionsInfo["SurfaceComplex"]:
1517 PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["ComplexHydrophobicSurface"])
1518
1519
1520 def SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID):
1521 """Setup groups and objects for chain."""
1522
1523 PDBGroupName = PyMOLObjectNames["PDBGroup"]
1524
1525 PyMOLObjectNames["Chains"][ChainID] = {}
1526 PyMOLObjectNames["Ligands"][ChainID] = {}
1527
1528 # Set up chain group and chain objects...
1529 ChainGroupName = "%s.Chain%s" % (PDBGroupName, ChainID)
1530 PyMOLObjectNames["Chains"][ChainID]["ChainGroup"] = ChainGroupName
1531 PyMOLObjectNames["PDBGroupMembers"].append(ChainGroupName)
1532 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"] = []
1533
1534 # Setup chain complex group and objects...
1535 ChainComplexGroupName = "%s.Complex" % (ChainGroupName)
1536 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"] = ChainComplexGroupName
1537 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainComplexGroupName)
1538
1539 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"] = []
1540
1541 Name = "%s.Complex" % (ChainComplexGroupName)
1542 PyMOLObjectNames["Chains"][ChainID]["ChainComplex"] = Name
1543 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
1544
1545 if OptionsInfo["SurfaceChainComplex"]:
1546 Name = "%s.Surface" % (ChainComplexGroupName)
1547 PyMOLObjectNames["Chains"][ChainID]["ChainComplexHydrophobicSurface"] = Name
1548 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
1549
1550 # Setup up a group for individual chains...
1551 ChainAloneGroupName = "%s.Chain" % (ChainGroupName)
1552 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"] = ChainAloneGroupName
1553 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainAloneGroupName)
1554
1555 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"] = []
1556
1557 Name = "%s.Chain" % (ChainAloneGroupName)
1558 PyMOLObjectNames["Chains"][ChainID]["ChainAlone"] = Name
1559 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
1560
1561 # Setup a group for non-interface residues...
1562 NonInterfaceGroupName = "%s.NonInterface" % (ChainAloneGroupName)
1563 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroup"] = NonInterfaceGroupName
1564 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(NonInterfaceGroupName)
1565
1566 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"] = []
1567
1568 # Setup a chain for non-interface residues...
1569 Name = "%s.Chain" % (NonInterfaceGroupName)
1570 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterface"] = Name
1571 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"].append(Name)
1572
1573 if GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
1574 # Setup a surface group and add it to chain alone non-interface group...
1575 SurfaceGroupName = "%s.Surface" % (NonInterfaceGroupName)
1576 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroup"] = SurfaceGroupName
1577 PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"].append(SurfaceGroupName)
1578
1579 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"] = []
1580
1581 # Setup a generic colored surface...
1582 Name = "%s.Surface" % (SurfaceGroupName)
1583 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurface"] = Name
1584 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(Name)
1585
1586 if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
1587 # Setup hydrophobicity surface...
1588 Name = "%s.Hydrophobicity" % (SurfaceGroupName)
1589 PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicSurface"] = Name
1590 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(Name)
1591
1592 # Setup hydrophobicity and charge surface...
1593 Name = "%s.Hydrophobicity_Charge" % (SurfaceGroupName)
1594 PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicChargeSurface"] = Name
1595 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(Name)
1596
1597 if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
1598 # Setup electrostatics group...
1599 GroupName = "%s.Vacuum_Electrostatics" % (SurfaceGroupName)
1600 PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroup"] = GroupName
1601 PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(GroupName)
1602
1603 # Setup electrostatics group members...
1604 PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroupMembers"] = []
1605
1606 for MemberType in ["Chain", "Contact_Potential", "Map", "Legend", "Volume"]:
1607 MemberID = re.sub("_", "", MemberType)
1608
1609 Name = "%s.%s" % (GroupName, MemberType)
1610 NameID = "ChainAloneElectrostaticsSurface%s" % MemberID
1611
1612 PyMOLObjectNames["Chains"][ChainID][NameID] = Name
1613 PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroupMembers"].append(Name)
1614
1615 # Setup solvent and inorganic objects for chain...
1616 for NameID in ["Solvent", "Inorganic"]:
1617 Name = "%s.%s" % (ChainGroupName, NameID)
1618 PyMOLObjectNames["Chains"][ChainID][NameID] = Name
1619 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(Name)
1620
1621
1622 def SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID):
1623 """Stetup groups and objects for ligand."""
1624
1625 PyMOLObjectNames["Ligands"][ChainID][LigandID] = {}
1626
1627 ChainGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainGroup"]
1628
1629 # Setup a chain level ligand group...
1630 ChainLigandGroupName = "%s.Ligand%s" % (ChainGroupName, LigandID)
1631 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"] = ChainLigandGroupName
1632 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainLigandGroupName)
1633
1634 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"] = []
1635
1636 # Set up ligand group and its members...
1637 GroupName = "%s.Ligand" % (ChainLigandGroupName)
1638 GroupNameID = "LigandGroup"
1639 GroupMembersID = "LigandGroupMembers"
1640
1641 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID] = GroupName
1642 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"].append(GroupName)
1643
1644 LigandName = "%s.Ligand" % (GroupName)
1645 LigandNameID = "Ligand"
1646 PyMOLObjectNames["Ligands"][ChainID][LigandID][LigandNameID] = LigandName
1647
1648 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID] = []
1649 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(LigandName)
1650
1651 # Add ball and stick...
1652 BallAndStickName = "%s.BallAndStick" % (GroupName)
1653 BallAndStickID = "LigandBallAndStick"
1654 PyMOLObjectNames["Ligands"][ChainID][LigandID][BallAndStickID] = BallAndStickName
1655 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(BallAndStickName)
1656
1657
1658 def SetupPyMOLInterfaceObjectNamesInfo():
1659 """Setup PyMOL object names for displaying macromolecular interfaces."""
1660
1661 InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
1662
1663 PyMOLObjectNames = {}
1664 PyMOLObjectNames["InterfaceIDs"] = {}
1665 PyMOLObjectNames["InterfaceChainIDs"] = {}
1666
1667 # Setup top level interfaces group...
1668 InterfacesGroupName = "Interfaces"
1669 PyMOLObjectNames["InterfacesGroup"] = InterfacesGroupName
1670 PyMOLObjectNames["InterfacesGroupMembers"] = []
1671
1672 for InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
1673 PyMOLObjectNames["InterfaceIDs"][InterfaceID] = {}
1674 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID] = {}
1675
1676 # Setup an interface group...
1677 InterfaceIDGroupName = "%s.%s" % (InterfacesGroupName, InterfaceID)
1678 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroup"] = InterfaceIDGroupName
1679 PyMOLObjectNames["InterfacesGroupMembers"].append(InterfaceIDGroupName)
1680 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"] = []
1681
1682 # Setup a polar contact group...
1683 if OptionsInfo["InterfacePolarContacts"]:
1684 PolarContactName = "%s.Polar_Contacts" % (InterfaceIDGroupName)
1685 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["PolarContacts"] = PolarContactName
1686 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"].append(PolarContactName)
1687
1688 # Setup a hydrophobic contact group...
1689 if OptionsInfo["InterfaceHydrophobicContacts"]:
1690 HydrophobicContactsName = "%s.Hydrophobic_Contacts" % (InterfaceIDGroupName)
1691 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["HydrophobicContacts"] = HydrophobicContactsName
1692 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"].append(HydrophobicContactsName)
1693
1694 for InterfaceChainID in InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID]:
1695 SetupPyMOLInterfaceObjectNamesForChain(PyMOLObjectNames, InterfaceID, InterfaceChainID)
1696
1697 OptionsInfo["InfilesInfo"]["PyMOLInterfaceObjectNamesInfo"] = PyMOLObjectNames
1698
1699
1700 def SetupPyMOLInterfaceObjectNamesForChain(PyMOLObjectNames, InterfaceID, InterfaceChainID):
1701 """Setup PyMOL interface object names for a chain."""
1702
1703 InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
1704 FileIndex = InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID]
1705 ChainID = InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID]
1706
1707 InterfaceIDGroupName = PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroup"]
1708
1709 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID] = {}
1710
1711 # Setup a chain group...
1712 ChainGroupName = "%s.%s" % (InterfaceIDGroupName, InterfaceChainID)
1713 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroup"] = ChainGroupName
1714 PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"].append(ChainGroupName)
1715 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"] = []
1716
1717 # Setup chain...
1718 Name = "%s.Chain" % (ChainGroupName)
1719 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["Chain"] = Name
1720 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"].append(Name)
1721
1722 if GetInterfaceResidueTypesStatus(FileIndex, ChainID):
1723 # Setup residue type group and its subgroups...
1724 ResiduesGroupName = "%s.Residues" % (ChainGroupName)
1725
1726 ResiduesGroupIDPrefix = "ChainResidues"
1727 ResiduesGroupID = "%sGroup" % ResiduesGroupIDPrefix
1728
1729 # Add residue group to chain group...
1730 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupID] = ResiduesGroupName
1731 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"].append(
1732 ResiduesGroupName
1733 )
1734
1735 # Initialize residue group members...
1736 ResiduesGroupMembersID = "%sGroupMembers" % ResiduesGroupIDPrefix
1737 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupMembersID] = []
1738
1739 # Setup residues sub groups and its members...
1740 for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
1741 SubGroupID = re.sub("_", "", SubGroupType)
1742
1743 ResiduesSubGroupName = "%s.%s" % (ResiduesGroupName, SubGroupType)
1744 ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupIDPrefix, SubGroupID)
1745
1746 # Add sub group to residues group...
1747 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupID] = (
1748 ResiduesSubGroupName
1749 )
1750 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupMembersID].append(
1751 ResiduesSubGroupName
1752 )
1753
1754 # Initialize sub group members...
1755 ResiduesSubGroupMembersID = "%s%sGroupMembers" % (ResiduesGroupIDPrefix, SubGroupID)
1756 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupMembersID] = []
1757
1758 # Add sub group members to subgroup...
1759 for MemberType in ["Residues", "Surface"]:
1760 MemberID = re.sub("_", "", MemberType)
1761
1762 SubGroupMemberName = "%s.%s" % (ResiduesSubGroupName, MemberType)
1763 SubGroupMemberID = "%s%s%s" % (ResiduesGroupIDPrefix, SubGroupID, MemberID)
1764
1765 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][SubGroupMemberID] = (
1766 SubGroupMemberName
1767 )
1768 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupMembersID].append(
1769 SubGroupMemberName
1770 )
1771
1772 if GetInterfaceContainsSurfacesStatus(FileIndex, ChainID):
1773 # Setup a surface group and add it to chain group...
1774 SurfaceGroupName = "%s.Surface" % (ChainGroupName)
1775 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroup"] = SurfaceGroupName
1776 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"].append(
1777 SurfaceGroupName
1778 )
1779
1780 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"] = []
1781
1782 # Setup a generic colored surface...
1783 Name = "%s.Surface" % (SurfaceGroupName)
1784 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurface"] = Name
1785 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(Name)
1786
1787 if GetInterfaceSurfaceChainStatus(FileIndex, ChainID):
1788 # Setup hydrophobicity surface...
1789 Name = "%s.Hydrophobicity" % (SurfaceGroupName)
1790 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicSurface"] = Name
1791 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(
1792 Name
1793 )
1794
1795 # Setup hydrophobicity and charge surface...
1796 Name = "%s.Hydrophobicity_Charge" % (SurfaceGroupName)
1797 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicChargeSurface"] = Name
1798 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(
1799 Name
1800 )
1801
1802 if GetInterfaceSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
1803 # Setup electrostatics group...
1804 GroupName = "%s.Vacuum_Electrostatics" % (SurfaceGroupName)
1805 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroup"] = GroupName
1806 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(
1807 GroupName
1808 )
1809
1810 # Setup electrostatics group members...
1811 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroupMembers"] = []
1812
1813 for MemberType in ["Chain", "Contact_Potential", "Map", "Legend", "Volume"]:
1814 MemberID = re.sub("_", "", MemberType)
1815
1816 Name = "%s.%s" % (GroupName, MemberType)
1817 NameID = "ChainElectrostaticsSurface%s" % MemberID
1818
1819 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][NameID] = Name
1820 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][
1821 "ChainElectrostaticsGroupMembers"
1822 ].append(Name)
1823
1824
1825 def ProcessResidueTypesAndSurfaceOptions(FileIndex, SpecifiedChainsAndLigandsInfo):
1826 """Process residue types and surface options for chains and interfaces."""
1827
1828 SpecifiedChainsAndLigandsInfo["ChainSurfaces"] = {}
1829 SpecifiedChainsAndLigandsInfo["SurfaceChain"] = {}
1830 SpecifiedChainsAndLigandsInfo["SurfaceChainElectrostatics"] = {}
1831
1832 SpecifiedChainsAndLigandsInfo["InterfaceSurfaces"] = {}
1833 SpecifiedChainsAndLigandsInfo["SurfaceInterface"] = {}
1834 SpecifiedChainsAndLigandsInfo["SurfaceInterfaceElectrostatics"] = {}
1835
1836 SpecifiedChainsAndLigandsInfo["ResidueTypesInterface"] = {}
1837
1838 # Load infile...
1839 Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
1840 MolName = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
1841 pymol.cmd.load(Infile, MolName)
1842
1843 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1844 AminoAcidsPresent = PyMOLUtil.AreAminoAcidResiduesPresent(MolName, ChainID)
1845
1846 # Process surfaces for chains...
1847 if re.match("^auto$", OptionsInfo["SurfaceChain"], re.I):
1848 SurfaceChain = True if AminoAcidsPresent else False
1849 else:
1850 SurfaceChain = True if re.match("^yes$", OptionsInfo["SurfaceChain"], re.I) else False
1851 SpecifiedChainsAndLigandsInfo["SurfaceChain"][ChainID] = SurfaceChain
1852
1853 if re.match("^auto$", OptionsInfo["SurfaceChainElectrostatics"], re.I):
1854 SurfaceChainElectrostatics = True if AminoAcidsPresent else False
1855 else:
1856 SurfaceChainElectrostatics = (
1857 True if re.match("^yes$", OptionsInfo["SurfaceChainElectrostatics"], re.I) else False
1858 )
1859 SpecifiedChainsAndLigandsInfo["SurfaceChainElectrostatics"][ChainID] = SurfaceChainElectrostatics
1860
1861 # A colored surface is always created by default...
1862 ChainSurfaces = True
1863 SpecifiedChainsAndLigandsInfo["ChainSurfaces"][ChainID] = ChainSurfaces
1864
1865 # Process residue types and surfaces for interfaces...
1866 if re.match("^auto$", OptionsInfo["InterfaceSurface"], re.I):
1867 InterfaceSurface = True if AminoAcidsPresent else False
1868 else:
1869 InterfaceSurface = True if re.match("^yes$", OptionsInfo["InterfaceSurface"], re.I) else False
1870 SpecifiedChainsAndLigandsInfo["SurfaceInterface"][ChainID] = InterfaceSurface
1871
1872 if re.match("^auto$", OptionsInfo["InterfaceSurfaceElectrostatics"], re.I):
1873 InterfaceSurfaceElectrostatics = True if AminoAcidsPresent else False
1874 else:
1875 InterfaceSurfaceElectrostatics = (
1876 True if re.match("^yes$", OptionsInfo["InterfaceSurfaceElectrostatics"], re.I) else False
1877 )
1878 SpecifiedChainsAndLigandsInfo["SurfaceInterfaceElectrostatics"][ChainID] = InterfaceSurfaceElectrostatics
1879
1880 # A colored surface is always created by default...
1881 InterfaceSurfaces = True
1882 SpecifiedChainsAndLigandsInfo["InterfaceSurfaces"][ChainID] = InterfaceSurfaces
1883
1884 if re.match("^auto$", OptionsInfo["InterfaceResidueTypes"], re.I):
1885 InterfaceResidueTypes = True if AminoAcidsPresent else False
1886 else:
1887 InterfaceResidueTypes = True if re.match("^yes$", OptionsInfo["InterfaceResidueTypes"], re.I) else False
1888 SpecifiedChainsAndLigandsInfo["ResidueTypesInterface"][ChainID] = InterfaceResidueTypes
1889
1890 # Delete loaded object...
1891 pymol.cmd.delete(MolName)
1892
1893
1894 def GetInterfaceResidueTypesStatus(FileIndex, ChainID):
1895 """Get status of residue types for an interface."""
1896
1897 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["ResidueTypesInterface"][ChainID]
1898
1899
1900 def GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
1901 """Get status of surfaces present in chain alone object."""
1902
1903 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["ChainSurfaces"][ChainID]
1904
1905
1906 def GetInterfaceContainsSurfacesStatus(FileIndex, ChainID):
1907 """Get status of surfaces present in an interface."""
1908
1909 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["InterfaceSurfaces"][ChainID]
1910
1911
1912 def GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
1913 """Get status of hydrophobic surfaces for chain alone object."""
1914
1915 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceChain"][ChainID]
1916
1917
1918 def GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
1919 """Get status of electrostatics surfaces for chain alone object."""
1920
1921 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceChainElectrostatics"][ChainID]
1922
1923
1924 def GetInterfaceSurfaceChainStatus(FileIndex, ChainID):
1925 """Get status of hydrophobic surfaces for an interface."""
1926
1927 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceInterface"][ChainID]
1928
1929
1930 def GetInterfaceSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
1931 """Get status of hydrophobic surfaces for an interface."""
1932
1933 return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceInterfaceElectrostatics"][
1934 ChainID
1935 ]
1936
1937
1938 def CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo):
1939 """Check presence of valid ligand IDs."""
1940
1941 MiscUtil.PrintInfo("\nSpecified chain IDs: %s" % (", ".join(SpecifiedChainsAndLigandsInfo["ChainIDs"])))
1942
1943 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1944 if len(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]):
1945 MiscUtil.PrintInfo(
1946 "Chain ID: %s; Specified LigandIDs: %s"
1947 % (ChainID, ", ".join(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]))
1948 )
1949 else:
1950 MiscUtil.PrintInfo("Chain IDs: %s; Specified LigandIDs: None" % (ChainID))
1951 MiscUtil.PrintWarning(
1952 "No valid ligand IDs found for chain ID, %s. PyMOL groups and objects related to ligand and binding pockect won't be created."
1953 % (ChainID)
1954 )
1955
1956
1957 def RetrieveFirstChainID(FileIndex):
1958 """Get first chain ID."""
1959
1960 ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
1961
1962 FirstChainID = None
1963 if len(ChainsAndLigandsInfo["ChainIDs"]):
1964 FirstChainID = ChainsAndLigandsInfo["ChainIDs"][0]
1965
1966 return FirstChainID
1967
1968
1969 def ProcessResidueTypes():
1970 """Process residue types."""
1971
1972 ResidueTypesNamesInfo, ResidueTypesParamsInfo = PyMOLUtil.ProcessResidueTypesOptionsInfo(
1973 "-r, --residueTypes", OptionsInfo["ResidueTypes"]
1974 )
1975 OptionsInfo["ResidueTypesNames"] = ResidueTypesNamesInfo
1976 OptionsInfo["ResidueTypesParams"] = ResidueTypesParamsInfo
1977
1978
1979 def ProcessSurfaceAtomTypesColors():
1980 """Process surface atom types colors."""
1981
1982 AtomTypesColorNamesInfo = PyMOLUtil.ProcessSurfaceAtomTypesColorsOptionsInfo(
1983 "--surfaceAtomTypesColors", OptionsInfo["SurfaceAtomTypesColors"]
1984 )
1985 OptionsInfo["AtomTypesColorNames"] = AtomTypesColorNamesInfo
1986
1987
1988 def ProcessOptions():
1989 """Process and validate command line arguments and options."""
1990
1991 MiscUtil.PrintInfo("Processing options...")
1992
1993 # Validate options...
1994 ValidateOptions()
1995
1996 OptionsInfo["AllowEmptyObjects"] = True if re.match("^Yes$", Options["--allowEmptyObjects"], re.I) else False
1997
1998 OptionsInfo["Infiles"] = Options["--infiles"]
1999 OptionsInfo["InfilesNames"] = Options["--infileNames"]
2000
2001 OptionsInfo["IgnoreHydrogens"] = True if re.match("^Yes$", Options["--ignoreHydrogens"], re.I) else False
2002
2003 OptionsInfo["Overwrite"] = Options["--overwrite"]
2004 OptionsInfo["PMLOut"] = True if re.match("^Yes$", Options["--PMLOut"], re.I) else False
2005
2006 OptionsInfo["Outfile"] = Options["--outfile"]
2007 FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"])
2008 OptionsInfo["PSEOut"] = False
2009 if re.match("^pml$", FileExt, re.I):
2010 OptionsInfo["PMLOutfile"] = OptionsInfo["Outfile"]
2011 OptionsInfo["PMEOutfile"] = re.sub(".pml$", ".pme", OptionsInfo["Outfile"])
2012 elif re.match("^pse$", FileExt, re.I):
2013 OptionsInfo["PSEOut"] = True
2014 OptionsInfo["PSEOutfile"] = OptionsInfo["Outfile"]
2015 OptionsInfo["PMLOutfile"] = re.sub(".pse$", ".pml", OptionsInfo["Outfile"])
2016 if os.path.exists(OptionsInfo["PMLOutfile"]) and (not OptionsInfo["Overwrite"]):
2017 MiscUtil.PrintError(
2018 'The intermediate output file to be generated, %s, already exist. Use option "--ov" or "--overwrite" and try again.'
2019 % OptionsInfo["PMLOutfile"]
2020 )
2021
2022 OptionsInfo["InterfaceLabelColor"] = Options["--interfaceLabelColor"]
2023
2024 OptionsInfo["InterfaceContactsCutoff"] = float(Options["--interfaceContactsCutoff"])
2025
2026 OptionsInfo["InterfaceHydrophobicContactsColor"] = Options["--interfaceHydrophobicContactsColor"]
2027 OptionsInfo["InterfaceHydrophobicContacts"] = (
2028 True if re.match("^Yes$", Options["--interfaceHydrophobicContacts"], re.I) else False
2029 )
2030
2031 OptionsInfo["InterfacePolarContactsColor"] = Options["--interfacePolarContactsColor"]
2032 OptionsInfo["InterfacePolarContacts"] = (
2033 True if re.match("^Yes$", Options["--interfacePolarContacts"], re.I) else False
2034 )
2035
2036 OptionsInfo["InterfaceResidueTypes"] = Options["--interfaceResidueTypes"]
2037 OptionsInfo["InterfaceSurface"] = Options["--interfaceSurface"]
2038 OptionsInfo["InterfaceSurfaceElectrostatics"] = Options["--interfaceSurfaceElectrostatics"]
2039
2040 OptionsInfo["LabelFontID"] = int(Options["--labelFontID"])
2041
2042 Method = Options["--method"]
2043 MethodCutoff = Options["--methodCutoff"]
2044 if re.match("^auto$", MethodCutoff, re.I):
2045 if re.match("BySASAChange", Method, re.I):
2046 MethodCutoff = 1.0
2047 elif re.match("ByHeavyAtomsDistance", Method, re.I):
2048 MethodCutoff = 5.0
2049 elif re.match("ByCAlphaAtomsDistance", Method, re.I):
2050 MethodCutoff = 8.0
2051 else:
2052 MiscUtil.PrintError(
2053 'The method, %s, specified using "-m, --method" option is not a valid method.' % (Method)
2054 )
2055 else:
2056 MethodCutoff = float(Options["--methodCutoff"])
2057 OptionsInfo["Method"] = Method
2058 OptionsInfo["MethodCutoff"] = MethodCutoff
2059
2060 OptionsInfo["ResidueTypes"] = Options["--residueTypes"]
2061 ProcessResidueTypes()
2062
2063 OptionsInfo["SurfaceChain"] = Options["--surfaceChain"]
2064 OptionsInfo["SurfaceChainElectrostatics"] = Options["--surfaceChainElectrostatics"]
2065
2066 OptionsInfo["SurfaceChainComplex"] = True if re.match("^Yes$", Options["--surfaceChainComplex"], re.I) else False
2067 OptionsInfo["SurfaceComplex"] = True if re.match("^Yes$", Options["--surfaceComplex"], re.I) else False
2068
2069 # Retrieve surface colors...
2070 SurfaceColors = re.sub(" ", "", Options["--surfaceColors"])
2071 SurfaceColorsWords = SurfaceColors.split(",")
2072 if len(SurfaceColorsWords) != 2:
2073 MiscUtil.PrintError(
2074 'The number of comma delinited color names, %d, specified using "--surfaceColors" option, "%s", must be a 2.'
2075 % (len(SurfaceColorsWords), Options["--surfaceColors"])
2076 )
2077 OptionsInfo["SurfaceColors"] = SurfaceColors
2078 OptionsInfo["SurfaceInterfaceColor"] = SurfaceColorsWords[0]
2079 OptionsInfo["SurfaceNonInterfaceColor"] = SurfaceColorsWords[1]
2080
2081 OptionsInfo["SurfaceColorPalette"] = Options["--surfaceColorPalette"]
2082 OptionsInfo["SurfaceAtomTypesColors"] = Options["--surfaceAtomTypesColors"]
2083 ProcessSurfaceAtomTypesColors()
2084
2085 OptionsInfo["SurfaceTransparency"] = float(Options["--surfaceTransparency"])
2086
2087 RetrieveInfilesInfo()
2088
2089 # Retrieve interface chain IDs...
2090 InterfaceChainIDs = re.sub(" ", "", Options["--chainIDs"])
2091 InterfaceChainIDsList = []
2092 if not re.match("^auto$", InterfaceChainIDs, re.I):
2093 InterfaceChainIDsWords = InterfaceChainIDs.split(",")
2094 if len(InterfaceChainIDsWords) % 2:
2095 MiscUtil.PrintError(
2096 'The number of comma delimited chain IDs, %d, specified using "-c, --chainIDs" option, "%s", must be a multple of 2.'
2097 % (len(InterfaceChainIDsWords), Options["--chainIDs"])
2098 )
2099 for ChainID in InterfaceChainIDsWords:
2100 if not len(ChainID):
2101 MiscUtil.PrintError(
2102 'A chain ID specified, "%s" using "-c, --chainIDs" option is empty.' % (Options["--chainIDs"])
2103 )
2104 ChainIDWords = ChainID.split("+")
2105 InterfaceChainIDsList.append(ChainIDWords)
2106 OptionsInfo["InterfaceChainIDs"] = InterfaceChainIDs
2107 OptionsInfo["InterfaceChainIDsList"] = InterfaceChainIDsList
2108
2109 # Process interface chain IDs...
2110 OptionsInfo["LigandIDs"] = Options["--ligandIDs"]
2111 ProcessInterfaceChainIDs()
2112
2113
2114 def RetrieveOptions():
2115 """Retrieve command line arguments and options."""
2116
2117 # Get options...
2118 global Options
2119 Options = docopt(_docoptUsage_)
2120
2121 # Set current working directory to the specified directory...
2122 WorkingDir = Options["--workingdir"]
2123 if WorkingDir:
2124 os.chdir(WorkingDir)
2125
2126 # Handle examples option...
2127 if "--examples" in Options and Options["--examples"]:
2128 MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
2129 sys.exit(0)
2130
2131
2132 def ValidateOptions():
2133 """Validate option values."""
2134
2135 MiscUtil.ValidateOptionTextValue("--allowEmptyObjects", Options["--allowEmptyObjects"], "yes no")
2136
2137 # Expand infiles to handle presence of multiple input files...
2138 InfileNames = MiscUtil.ExpandFileNames(Options["--infiles"], ",")
2139 InfilesCount = len(InfileNames)
2140 if not InfilesCount:
2141 MiscUtil.PrintError('No input files specified for "-i, --infiles" option')
2142
2143 # Validate file extensions...
2144 for Infile in InfileNames:
2145 MiscUtil.ValidateOptionFilePath("-i, --infiles", Infile)
2146 MiscUtil.ValidateOptionFileExt("-i, --infiles", Infile, "pdb cif")
2147 MiscUtil.ValidateOptionsDistinctFileNames("-i, --infiles", Infile, "-o, --outfile", Options["--outfile"])
2148
2149 # Validate file count...
2150 if InfilesCount > 2:
2151 MiscUtil.PrintError(
2152 'Number of input files, %s, specified using "-i, --infiles" option is not valid. Number of allowed files: 1 or 2'
2153 % (InfilesCount)
2154 )
2155
2156 # Validate distinct file names...
2157 if InfilesCount == 2:
2158 Infile1Name, Infile2Name = InfileNames
2159 Infile1Pattern = r"^" + re.escape(Infile1Name) + r"$"
2160 if re.match(Infile1Pattern, Infile2Name, re.I):
2161 MiscUtil.PrintError(
2162 'The file names specified, "%s", for option "-i, --infiles" must be different.\n'
2163 % (Options["--infiles"])
2164 )
2165
2166 Options["--infileNames"] = InfileNames
2167
2168 MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "pml pse")
2169 MiscUtil.ValidateOptionsOutputFileOverwrite(
2170 "-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"]
2171 )
2172
2173 MiscUtil.ValidateOptionTextValue("--ignoreHydrogens", Options["--ignoreHydrogens"], "yes no")
2174
2175 MiscUtil.ValidateOptionFloatValue("--interfaceContactsCutoff", Options["--interfaceContactsCutoff"], {">": 0.0})
2176 MiscUtil.ValidateOptionTextValue(
2177 "--interfaceHydrophobicContacts", Options["--interfaceHydrophobicContacts"], "yes no"
2178 )
2179 MiscUtil.ValidateOptionTextValue("--interfacePolarContacts", Options["--interfacePolarContacts"], "yes no")
2180
2181 MiscUtil.ValidateOptionTextValue("--interfaceResidueTypes", Options["--interfaceResidueTypes"], "yes no auto")
2182 MiscUtil.ValidateOptionTextValue("--interfaceSurface", Options["--interfaceSurface"], "yes no auto")
2183 MiscUtil.ValidateOptionTextValue(
2184 "--interfaceSurfaceElectrostatics", Options["--interfaceSurfaceElectrostatics"], "yes no auto"
2185 )
2186
2187 MiscUtil.ValidateOptionIntegerValue("--labelFontID", Options["--labelFontID"], {})
2188
2189 MiscUtil.ValidateOptionTextValue(
2190 "--method", Options["--method"], "BySASAChange ByHeavyAtomsDistance ByCAlphaAtomsDistance"
2191 )
2192 if not re.match("^auto$", Options["--methodCutoff"], re.I):
2193 MiscUtil.ValidateOptionFloatValue("--methodCutoff", Options["--methodCutoff"], {">": 0.0})
2194
2195 MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
2196
2197 MiscUtil.ValidateOptionTextValue("--surfaceChain", Options["--surfaceChain"], "yes no auto")
2198 MiscUtil.ValidateOptionTextValue(
2199 "--surfaceChainElectrostatics", Options["--surfaceChainElectrostatics"], "yes no auto"
2200 )
2201 MiscUtil.ValidateOptionTextValue("--surfaceComplex", Options["--surfaceComplex"], "yes no")
2202 MiscUtil.ValidateOptionTextValue("--surfaceChainComplex", Options["--surfaceChainComplex"], "yes no")
2203
2204 MiscUtil.ValidateOptionTextValue(
2205 "--surfaceColorPalette", Options["--surfaceColorPalette"], "RedToWhite WhiteToGreen"
2206 )
2207 MiscUtil.ValidateOptionFloatValue("--surfaceTransparency", Options["--surfaceTransparency"], {">=": 0.0, "<=": 1.0})
2208
2209
2210 # Setup a usage string for docopt...
2211 _docoptUsage_ = """
2212 PyMOLVisualizeInterfaces.py - Visualize macromolecular interfaces
2213
2214 Usage:
2215 PyMOLVisualizeInterfaces.py [--allowEmptyObjects <yes or no>] [--chainIDs <ChainID1 or ChainID1,ChainID2>]
2216 [--interfaceLabelColor <text>] [ --interfaceContactsCutoff <number>]
2217 [--interfaceHydrophobicContacts <yes or no>] [--interfaceHydrophobicContactsColor <text>]
2218 [--interfacePolarContacts <yes or no>] [--interfacePolarContactsColor <text>]
2219 [--interfaceResidueTypes <yes or no>] [--interfaceSurface <yes or no>]
2220 [--interfaceSurfaceElectrostatics <yes or no>] [--labelFontID <number>]
2221 [--ignoreHydrogens <yes or no>] [--ligandIDs <Largest, All, None or ID1,ID2...>]
2222 [--method <text>] [--methodCutoff <number>]
2223 [--PMLOut <yes or no>] [--residueTypes <Type,Color,ResNames,...>] [--surfaceChain <yes or no>]
2224 [--surfaceChainElectrostatics <yes or no>] [--surfaceChainComplex <yes or no>]
2225 [--surfaceComplex <yes or no>] [--surfaceColors <ColorName1,ColorName2>]
2226 [--surfaceColorPalette <RedToWhite or WhiteToGreen>]
2227 [--surfaceAtomTypesColors <ColorType,ColorSpec,...>] [--surfaceTransparency <number>]
2228 [--overwrite] [-w <dir>] -i <infile1,...> -o <outfile>
2229 PyMOLVisualizeInterfaces.py -h | --help | -e | --examples
2230
2231 Description:
2232 Generate PyMOL visualization files for viewing interfaces between macromolecules
2233 including proteins and nucleic acids. The interfaces may be generated between
2234 pairs of chains in a single file or across two different files.
2235
2236 The supported input file format are: PDB (.pdb), CIF (.cif)
2237
2238 The supported output file formats are: PyMOL script file (.pml), PyMOL session
2239 file (.pse)
2240
2241 A variety of PyMOL groups and objects may be created for visualization of
2242 macromolecular interfaces. These groups and objects correspond to complexes,
2243 surfaces, chains, ligands, and interfaces. A complete hierarchy of all possible
2244 PyMOL groups and objects is shown below:
2245
2246 <PDBFileRoot>
2247 .Complex
2248 .Complex
2249 .Surface
2250 .Chain<ID>
2251 .Complex
2252 .Complex
2253 .Surface
2254 .Chain
2255 .Chain
2256 .NonInterface
2257 .Chain
2258 .Surface
2259 .Surface
2260 .Hydrophobicity
2261 .Hydrophobicity_Charge
2262 .Vacuum_Electrostatics
2263 .Contact_Potentials
2264 .Map
2265 .Legend
2266 .Volume
2267 .Solvent
2268 .Inorganic
2269 .Ligand<ID>
2270 .Ligand
2271 .Ligand
2272 .BallAndStick
2273 .Ligand<ID>
2274 .Ligand
2275 ... ... ...
2276 .Chain<ID>
2277 ... ... ...
2278 .Ligand<ID>
2279 ... ... ...
2280 .Ligand<ID>
2281 ... ... ...
2282 .Chain<ID>
2283 ... ... ...
2284 <PDBFileRoot>
2285 .Complex
2286 ... ... ...
2287 .Chain<ID>
2288 ... ... ...
2289 .Ligand<ID>
2290 ... ... ...
2291 .Ligand<ID>
2292 ... ... ...
2293 .Chain<ID>
2294 ... ... ...
2295 <Interfaces>
2296 .Chain<IDs1>_Chain<IDs2>
2297 .Polar_Contacts
2298 .Hydrophobic_Contacts
2299 .Chain<ID> or Chain<ID>_<PDBFileRoot>
2300 .Chain
2301 .Residues
2302 .Aromatic
2303 .Residues
2304 .Surface
2305 .Hydrophobic
2306 .Residues
2307 .Surface
2308 .Polar
2309 .Residues
2310 .Surface
2311 .Positively_Charged
2312 .Residues
2313 .Surface
2314 .Negatively_Charged
2315 .Residues
2316 .Surface
2317 .Other
2318 .Residues
2319 .Surface
2320 .Surface
2321 .Surface
2322 .Hydrophobicity
2323 .Hydrophobicity_Charge
2324 .Vacuum_Electrostatics
2325 .Contact_Potentials
2326 .Map
2327 .Legend
2328 .Volume
2329 .Chain<ID> or <PDBFileRoot>_Chain<ID>
2330 .Chain
2331 .Residues
2332 ... ... ...
2333 .Surface
2334 ... ... ...
2335 .Chain<IDs>_Chain<IDs>
2336 .Polar_Contacts
2337 .Hydrophobic_Contacts
2338 .Chain<ID> or Chain<ID>_<PDBFileRoot>
2339 .Chain
2340 .Residues
2341 ... ... ...
2342 .Surface
2343 ... ... ...
2344 .Chain<ID> or Chain<ID>_<PDBFileRoot>
2345 .Chain
2346 .Residues
2347 ... ... ...
2348 .Surface
2349 ... ... ...
2350
2351 The hydrophobic and electrostatic surfaces are not created for complete complex
2352 and chain complex in input file(s) by default. A word to the wise: The creation of
2353 surface objects may slow down loading of PML file and generation of PSE file, based
2354 on the size of input complexes. The generation of PSE file may also fail.
2355
2356 Options:
2357 --allowEmptyObjects <yes or no> [default: no]
2358 Allow creation of empty PyMOL objects corresponding to interface,
2359 solvent, and inorganic atom selections across chains and ligands in
2360 input file(s). By default, the empty objects are marked for deletion.
2361 -c, --chainIDs <ChainID1,ChainD2,...> [default: Auto]
2362 Pairwise comma delimited list of chain IDs for the identification of
2363 macromolecular interfaces. All chain IDs must be present in the
2364 same file for a single input file. Otherwise, the first and second
2365 chain ID(s) in a pair belong to the first and second input file.
2366
2367 The default values for interface chain IDs depend on the number
2368 of input files as shown below:
2369
2370 One input file: First two chains
2371 Two input files: First chain in each input file
2372
2373 Each chain may contain multiple chain IDs delimited by a plus sign. For
2374 example, A+B,C+D chain pair specifies interface between chain complexes
2375 A+B and C+D in first input file or across two input files.
2376 -e, --examples
2377 Print examples.
2378 -h, --help
2379 Print this help message.
2380 -i, --infiles <infile or infile1,infile2>
2381 Name of an input file or a comma delmited list of names for two input
2382 files.
2383 --ignoreHydrogens <yes or no> [default: yes]
2384 Ignore hydrogens for ligand views.
2385 --interfaceLabelColor <text> [default: magenta]
2386 Color for drawing residue or atom level labels for residues in an interface.
2387 The specified value must be valid color. No validation is performed.
2388 --interfaceContactsCutoff <number> [default: 4.0]
2389 Distance in Angstroms for identifying polar and hyrdophobic contacts
2390 between atoms in interface reisudes.
2391 --interfaceHydrophobicContacts <yes or no> [default: yes]
2392 Hydrophobic contacts between residues in an interface. The hydrophobic
2393 contacts are shown between pairs of carbon atoms not connected to
2394 hydrogen bond donor or acceptors atoms as identified by PyMOL.
2395 --interfaceHydrophobicContactsColor <text> [default: purpleblue]
2396 Color for drawing hydrophobic contacts between residues in an interface.
2397 The specified value must be valid color. No validation is performed.
2398 --interfacePolarContacts <yes or no> [default: yes]
2399 Polar contacts between residues in an interface.
2400 --interfacePolarContactsColor <text> [default: orange]
2401 Color for drawing polar contacts between residues in an interface.
2402 The specified value must be valid color. No validation is performed.
2403 --interfaceResidueTypes <yes or no> [default: auto]
2404 Interface residue types. The residue groups are generated using residue types,
2405 colors, and names specified by '--residueTypes' option. It is only valid for
2406 amino acids. By default, the residue type groups are automatically created
2407 for interfaces containing amino acids and skipped for chains only containing
2408 nucleic acids.
2409 --interfaceSurface <yes or no> [default: auto]
2410 Surfaces around interface residues colored by hydrophobicity alone and
2411 both hydrophobicity and charge. The hydrophobicity surface is colored
2412 at residue level using Eisenberg hydrophobicity scale for residues and color
2413 gradient specified by '--surfaceColorPalette' option. The hydrophobicity and
2414 charge surface is colored [ Ref 140 ] at atom level using colors specified for
2415 groups of atoms by '--surfaceAtomTypesColors' option. This scheme allows
2416 simultaneous mapping of hyrophobicity and charge values on the surfaces.
2417
2418 This option is only valid for amino acids. By default, both surfaces are
2419 automatically created for pockets containing amino acids and skipped for
2420 pockets containing only nucleic acids.
2421
2422 In addition, generic surfaces colored by '--surfaceColors' are always created
2423 for interface residues containing amino acids and nucleic acids.
2424 --interfaceSurfaceElectrostatics <yes or no> [default: no]
2425 Vacuum electrostatics contact potential surface around interface residues.
2426 A word to the wise from PyMOL documentation: The computed protein
2427 contact potentials are only qualitatively useful, due to short cutoffs,
2428 truncation, and lack of solvent "screening".
2429
2430 This option is only valid for amino acids. By default, the electrostatics surface
2431 is automatically created for chains containing amino acids and skipped for chains
2432 containing only nucleic acids.
2433 --labelFontID <number> [default: 7]
2434 Font ID for drawing labels. Default: 7 (Sans Bold). Valid values: 5 to 16.
2435 The specified value must be a valid PyMOL font ID. No validation is
2436 performed. The complete lists of valid font IDs is available at:
2437 pymolwiki.org/index.php/Label_font_id. Examples: 5 - Sans;
2438 7 - Sans Bold; 9 - Serif; 10 - Serif Bold.
2439 -l, --ligandIDs <Largest, All, None or ID1,ID2...> [default: All]
2440 List of ligand IDs to show in chains during visualization of interfaces. Possible
2441 values: Largest, All, None, or a comma delimited list of ligand IDs. The
2442 default is to show all ligands present in chains involved in interfaces.
2443
2444 Ligands are identified using organic selection operator available in PyMOL.
2445 It'll also identify buffer molecules as ligands. The largest ligand contains
2446 the highest number of heavy atoms.
2447 -m, --method <text> [default: BySASAChange]
2448 Methodology for the identification of interface residues between a pair
2449 of chains in an input file. The interface residues may be identified by
2450 change in solvent accessible surface area (SASA) for a residue between
2451 a chain and chains complex, distance between heavy atoms
2452 in two chains, or distance between CAlpha atoms. Possible values:
2453 BySASAChange, ByHeavyAtomsDistance, or ByCAlphaAtomsDistance.
2454 --methodCutoff <number> [default: auto]
2455 Cutoff value used by different methodologies during the identification of
2456 interface residues between a pair of chains. The default values are
2457 shown below:
2458
2459 BySASAChange: 1.0; Units: Angstrom**2 [ Ref 141 ]
2460 ByHeavyAtomsDistance: 5.0; Units: Angstrom [ Ref 142 ]
2461 ByCAlphaAtomsDistance: 8.0; Units: Angstrom [ Ref 143 ]
2462
2463 -o, --outfile <outfile>
2464 Output file name.
2465 -p, --PMLOut <yes or no> [default: yes]
2466 Save PML file during generation of PSE file.
2467 -r, --residueTypes <Type,Color,ResNames,...> [default: auto]
2468 Residue types, colors, and names to generate for residue groups during
2469 and '--residueTypesChain' option. It is only valid for amino acids.
2470
2471 It is a triplet of comma delimited list of amino acid residues type, residues
2472 color, and a space delimited list three letter residue names.
2473
2474 The default values for residue type, color, and name triplets are shown
2475 below:
2476
2477 Aromatic,brightorange,HIS PHE TRP TYR,
2478 Hydrophobic,orange,ALA GLY VAL LEU ILE PRO MET,
2479 Polar,palegreen,ASN GLN SER THR CYS,
2480 Positively_Charged,marine,ARG LYS,
2481 Negatively_Charged,red,ASP GLU
2482
2483 The color name must be a valid PyMOL name. No validation is performed.
2484 An amino acid name may appear across multiple residue types. All other
2485 residues are grouped under 'Other'.
2486 --surfaceChain <yes or no> [default: auto]
2487 Surfaces around non-interface residues in individual chain colored by
2488 hydrophobicity alone and both hydrophobicity and charge. The hydrophobicity
2489 surface is colored at residue level using Eisenberg hydrophobicity scale for residues
2490 and color gradient specified by '--surfaceColorPalette' option. The hydrophobicity
2491 and charge surface is colored [ Ref 140 ] at atom level using colors specified for
2492 groups of atoms by '--surfaceAtomTypesColors' option. This scheme allows
2493 simultaneous mapping of hyrophobicity and charge values on the surfaces.
2494
2495 This option is only valid for amino acids. By default, both surfaces are
2496 automatically created for chains containing amino acids and skipped for
2497 chains containing only nucleic acids.
2498
2499 In addition, generic surfaces colored by '--surfaceColors' are always created
2500 for non-interface residues containing amino acids and nucleic acids.
2501 --surfaceChainElectrostatics <yes or no> [default: no]
2502 Vacuum electrostatics contact potential surface and volume around non-interface
2503 residues in individual chain. A word to the wise from PyMOL documentation: The
2504 computed protein contact potentials are only qualitatively useful, due to short cutoffs,
2505 truncation, and lack of solvent "screening".
2506
2507 This option is only valid for amino acids. By default, the electrostatics surface
2508 and volume are automatically created for chains containing amino acids and
2509 skipped for chains containing only nucleic acids.
2510 --surfaceChainComplex <yes or no> [default: no]
2511 Hydrophobic surface around chain complex. The surface is colored by
2512 hydrophobicity. It is only valid for amino acids.
2513 --surfaceComplex <yes or no> [default: no]
2514 Hydrophobic surface around complete complex. The surface is colored by
2515 hydrophobicity. It is only valid for amino acids.
2516 --surfaceColors <ColorName1,ColorName2> [default: salmon,lightblue]
2517 Color names for surfaces around interface residues and non-interface
2518 residues in chains. These colors are not used for surfaces colored by
2519 hydrophobicity and charge. The color names must be valid PyMOL names.
2520 --surfaceColorPalette <RedToWhite or WhiteToGreen> [default: RedToWhite]
2521 Color palette for hydrophobic surfaces around chains and interface residues
2522 in proteins. Possible values: RedToWhite or WhiteToGreen from most
2523 hydrophobic amino acid to least hydrophobic. The colors values for amino
2524 acids are taken from color_h script available as part of the Script Library at
2525 PyMOL Wiki.
2526 --surfaceAtomTypesColors <ColorType,ColorSpec,...> [default: auto]
2527 Atom colors for generating surfaces colored by hyrophobicity and charge
2528 around chains and interface residues in proteins. It's a pairwise comma
2529 delimited list of atom color type and color specification for goups of atoms.
2530
2531 The default values for color types [ Ref 140 ] along wth color specifications
2532 are shown below:
2533
2534 HydrophobicAtomsColor, yellow,
2535 NegativelyChargedAtomsColor, red,
2536 PositivelyChargedAtomsColor, blue,
2537 OtherAtomsColor, gray90
2538
2539 The color names must be valid PyMOL names.
2540
2541 The color values may also be specified as space delimited RGB triplets:
2542
2543 HydrophobicAtomsColor, 0.95 0.78 0.0,
2544 NegativelyChargedAtomsColor, 1.0 0.4 0.4,
2545 PositivelyChargedAtomsColor, 0.2 0.5 0.8,
2546 OtherAtomsColor, 0.95 0.95 0.95
2547
2548 --surfaceTransparency <number> [default: 0.25]
2549 Surface transparency for molecular surfaces.
2550 --overwrite
2551 Overwrite existing files.
2552 -w, --workingdir <dir>
2553 Location of working directory which defaults to the current directory.
2554
2555 Examples:
2556 To visualize interface residues between the first two chains in a PDB file,
2557 using default methodology to identify interfaces, and and generate a PML
2558 file, type:
2559
2560 % PyMOLVisualizeInterfaces.py -i Sample8.pdb -o Sample8.pml
2561
2562 To visualize interface residues between a pair of specific chains in a PDB
2563 file using a specific methodology and cutoff value to identify interfaces, and
2564 generate a PML file, type:
2565
2566 % PyMOLVisualizeInterfaces.py -m BySASAChange --methodCutoff 1.0
2567 -c "A,B" -i Sample8.pdb -o Sample8.pml
2568
2569 To visualize interface residues between multiple pairs of specified chains in
2570 a PDB file using a specific methodology and cutoff value to identify interfaces,
2571 and generate a PML file, type:
2572
2573 % PyMOLVisualizeInterfaces.py -m ByHeavyAtomsDistance
2574 --methodCutoff 5.0 -c "A,B,B,D" -i Sample8.pdb -o Sample8.pml
2575
2576 To visualize interface residues between a pair of specified chains, each member
2577 containing multiple chains, a PDB file using a specific methodology and cutoff
2578 value to identify interfaces, and generate a PML file, type:
2579
2580 % PyMOLVisualizeInterfaces.py -m ByCAlphaAtomsDistance
2581 --methodCutoff 8.0 -c "A+C,B+D" -i Sample8.pdb -o Sample8.pml
2582
2583 To visualize interface residues between a pair of specific chains across two PDB
2584 files using a specific methodology and cutoff value to identify interfaces, and
2585 generate a PML file, type:
2586
2587 % PyMOLVisualizeInterfaces.py -m BySASAChange --methodCutoff 1.0
2588 -c "A,B" -i Sample8Part1.pdb,Sample8Part2.pdb
2589 -o Sample8.pml
2590
2591 To visualize interface residues between multiple pairs of specified chains across
2592 two PDB files using a specific methodology and cutoff value to identify interfaces,
2593 and generate a PML file, type:
2594
2595 % PyMOLVisualizeInterfaces.py -m ByHeavyAtomsDistance
2596 --methodCutoff 5.0 -c "A,B,C,B" -i Sample8Part1.pdb,Sample8Part2.pdb
2597 -o Sample8.pml
2598
2599 To visualize interface residues between a pair of specified chains, each member
2600 containing multiple chains, across two PDB files using a specific methodology
2601 and cutoff value to identify interfaces, and generate a PML file, type:
2602
2603 % PyMOLVisualizeInterfaces.py -m ByCAlphaAtomsDistance
2604 --methodCutoff 8.0 -c "A+C,B+D" -i "Sample8Part1.pdb,Sample8Part2.pdb"
2605 -o Sample8.pml
2606
2607 Author:
2608 Manish Sud(msud@san.rr.com)
2609
2610 See also:
2611 DownloadPDBFiles.pl, PyMOLVisualizeCryoEMDensity.py,
2612 PyMOLVisualizeElectronDensity.py, PyMOLVisualizeMacromolecules.py,
2613 PyMOLVisualizeSurfaceAndBuriedResidues.py
2614
2615 Copyright:
2616 Copyright (C) 2025 Manish Sud. All rights reserved.
2617
2618 The functionality available in this script is implemented using PyMOL, a
2619 molecular visualization system on an open source foundation originally
2620 developed by Warren DeLano.
2621
2622 This file is part of MayaChemTools.
2623
2624 MayaChemTools is free software; you can redistribute it and/or modify it under
2625 the terms of the GNU Lesser General Public License as published by the Free
2626 Software Foundation; either version 3 of the License, or (at your option) any
2627 later version.
2628
2629 """
2630
2631 if __name__ == "__main__":
2632 main()