1 #
2 # File: PyMOLUtil.py
3 # Author: Manish Sud <msud@san.rr.com>
4 #
5 # Copyright (C) 2026 Manish Sud. All rights reserved.
6 #
7 # The functionality available in this file is implemented using PyMOL, a
8 # molecular visualization system on an open source foundation originally
9 # developed by Warren DeLano.
10 #
11 # This file is part of MayaChemTools.
12 #
13 # MayaChemTools is free software; you can redistribute it and/or modify it under
14 # the terms of the GNU Lesser General Public License as published by the Free
15 # Software Foundation; either version 3 of the License, or (at your option) any
16 # later version.
17 #
18 # MayaChemTools is distributed in the hope that it will be useful, but without
19 # any warranty; without even the implied warranty of merchantability of fitness
20 # for a particular purpose. See the GNU Lesser General Public License for more
21 # details.
22 #
23 # You should have received a copy of the GNU Lesser General Public License
24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
26 # Boston, MA, 02111-1307, USA.
27 #
28
29 from __future__ import print_function
30
31 import os
32 import re
33
34 from pymol import cmd, stored, CmdException
35
36 import MiscUtil
37
38 __all__ = [
39 "AreAminoAcidResiduesPresent",
40 "AreNucleicAcidResiduesPresent",
41 "CalculateCenterOfMass",
42 "ConvertFileFormat",
43 "ConvertPMLFileToPSEFile",
44 "GetCentroid",
45 "GetChains",
46 "GetChainsAndLigandsInfo",
47 "GetAminoAcidResiduesInfo",
48 "GetInorganicResiduesInfo",
49 "GetInterfaceChainsResiduesByCAlphaAtomsDistance",
50 "GetInterfaceChainsResiduesByHeavyAtomsDistance",
51 "GetInterfaceChainsResiduesBySASAChange",
52 "GetLargestLigand",
53 "GetLigandResiduesInfo",
54 "GetLigands",
55 "GetMolecules",
56 "GetNucleicAcidResiduesInfo",
57 "GetPocketInorganicResiduesInfo",
58 "GetPocketPolymerResiduesInfo",
59 "GetPocketSolventResiduesInfo",
60 "GetPolymerResiduesInfo",
61 "GetPhiPsiResiduesInfo",
62 "GetPhiPsiChainsAndResiduesInfo",
63 "GetPhiPsiCategoriesResiduesInfo",
64 "GetSelectionResiduesInfo",
65 "GetSolventResiduesInfo",
66 "GetSurfaceAndBuriedResiduesInfo",
67 "ProcessChainsAndLigandsOptionsInfo",
68 "ProcessChainSelectionsOptionsInfo",
69 "ProcessResidueTypesOptionsInfo",
70 "ProcessSaltBridgesChainResiduesOptionsInfo",
71 "ProcessSurfaceAtomTypesColorsOptionsInfo",
72 "SetupPMLForAlignment",
73 "SetupPMLForBFactorCartoonView",
74 "SetupPMLForBFactorPuttyView",
75 "SetupPMLForBallAndStickView",
76 "SetupPMLForDeepColoring",
77 "SetupPMLForDisulfideBondsView",
78 "SetupPMLForEnableDisable",
79 "SetupPMLForGroup",
80 "SetupPMLForHydrophobicSurfaceView",
81 "SetupPMLForHydrophobicAndChargeSurfaceView",
82 "SetupPMLForInorganicView",
83 "SetupPMLForLigandPocketInorganicView",
84 "SetupPMLForLigandPocketSolventView",
85 "SetupPMLForLigandPocketView",
86 "SetupPMLForLigandView",
87 "SetupPMLForLigandsInputFileView",
88 "SetupPMLForDistanceContactsView",
89 "SetupPMLForPiCationContactsView",
90 "SetupPMLForPiPiContactsView",
91 "SetupPMLForPolarContactsView",
92 "SetupPMLForHalogenContactsView",
93 "SetupPMLForHydrophobicContactsView",
94 "SetupPMLForPolymerChainComplexView",
95 "SetupPMLForPolymerChainView",
96 "SetupPMLForPolymerComplexView",
97 "SetupPMLForSolventView",
98 "SetupPMLForSaltBridgesResiduesView",
99 "SetupPMLForSurfaceView",
100 "SetupPMLForSelectionDisplayView",
101 "SetupPMLHeaderInfo",
102 ]
103
104
105 def GetMolecules(Selection="all"):
106 """Get names of molecule objects in a selection or all molecule objects.
107
108 Arguments:
109 Selection (str): A PyMOL selection.
110
111 Returns:
112 list: Names of molecule objects.
113
114 """
115 Names = cmd.get_object_list("(" + Selection + ")")
116
117 return Names
118
119
120 def GetChains(MoleculeName, RemoveEmpty=True):
121 """Get chain identifiers present in a molecule.
122
123 Arguments:
124 MoleculeName (str): Name of a PyMOL molecule object.
125 RemoveEmpty (bool): Remove empty chain ID from the list of chain IDs
126 returned by PyMOL.
127
128 Returns:
129 list: Names of chains present in a molecule, sorted alphabetically in a
130 ascending order.
131
132 """
133 if not len(MoleculeName):
134 return None
135
136 ChainIDs = []
137 try:
138 ChainIDs = cmd.get_chains("model %s" % MoleculeName)
139 except CmdException:
140 MiscUtil.PrintWarning("PyMOLUtil.GetChains: Invalid molecule name: %s" % MoleculeName)
141
142 if not len(ChainIDs):
143 return None
144
145 # Remove empty Chain IDs from the list...
146 if RemoveEmpty:
147 NonEmptyChainIDs = []
148 for ChainID in ChainIDs:
149 if len(ChainID):
150 NonEmptyChainIDs.append(ChainID)
151 if len(NonEmptyChainIDs) != len(ChainIDs):
152 MiscUtil.PrintInfo("PyMOLUtil.GetChains: Removing non-empty chain IDs from the list of chain IDs...")
153
154 ChainIDs = NonEmptyChainIDs
155
156 return ChainIDs
157
158
159 def GetChainsAndLigandsInfo(
160 Infile, MolName, Quite=False, LigandSortBy="Size", LigandSortOrder="Auto", LigandIgnoreHydrogens="Yes"
161 ):
162 """Get chain identifiers present in a molecule along with names of the
163 ligands present in chains. Ligands are identified using PyMOL 'organic'
164 selection.
165
166 Arguments:
167 Infile (str) : Name of a file.
168 MolName (str) : Name to use for PyMOL molecule object.
169 Quite (bool) : Flag
170 LigandSortBy (str): Sort ligand names alphabetically or by size. Possible
171 values: Alphabetical or Size
172 LigandSortOrder (str): Sort order for sorting ligands. Possible values:
173 Ascending, Descending, Auto. The 'Auto' value implies automatic
174 determination of sort order based on the value of 'SortBy'.
175 Automatic defaults: Descending for SortBy value of Size; Ascending
176 for SortBy value of Alphabetical.
177 LigandIgnoreHydrogens (str): Ignore hydrogens during determination of ligand
178 size.
179
180 Returns:
181 dict: A dictionary containing list of chain identifiers and dictionaries
182 of chains containing lists of ligand names for each chain. Names of
183 ligands present in chain for a molecule sorted by size or
184 alphabetically.
185
186 Examples:
187
188 ChainsAndLigandsInfo = GetChainsAndLigandsInfo(Infile, MolName)
189 for ChainID in ChainsAndLigandsInfo["ChainIDs"]:
190 for LigandID in ChainsAndLigandsInfo["LigandIDs"][ChainID]:
191 MiscUtil.PrintInfo("ChainID: %s; LigandID: %s" % (ChainID,
192 LigandID))
193
194 """
195 if not Quite:
196 MiscUtil.PrintInfo("\nRetrieving chain and ligand information from input file %s..." % Infile)
197
198 # Collect chains and ligands information with ligands sorted by size to be used for
199 # identification of largest ligand at the top...
200 cmd.load(Infile, MolName)
201 ChainsAndLigandsInfo = _GetChainsAndLigands(MolName, LigandSortBy="size", LigandSortOrder="descending")
202 cmd.delete(MolName)
203
204 # Print out chain and ligand IDs...
205 if not Quite:
206 ChainIDs = ", ".join(ChainsAndLigandsInfo["ChainIDs"]) if len(ChainsAndLigandsInfo["ChainIDs"]) else "None"
207 MiscUtil.PrintInfo("Chain IDs: %s" % ChainIDs)
208
209 for ChainID in ChainsAndLigandsInfo["ChainIDs"]:
210 LigandIDs = (
211 ", ".join(ChainsAndLigandsInfo["LigandIDs"][ChainID])
212 if len(ChainsAndLigandsInfo["LigandIDs"][ChainID])
213 else "None"
214 )
215 MiscUtil.PrintInfo("Chain ID: %s; LigandIDs: %s" % (ChainID, LigandIDs))
216
217 return ChainsAndLigandsInfo
218
219
220 def GetLigands(MoleculeName, ChainName, SortBy="Size", SortOrder="Auto", IgnoreHydrogens="Yes"):
221 """Get names of ligands present in a chain of a molecule. Ligands are
222 identified using PyMOL 'organic' selection.
223
224 Arguments:
225 MoleculeName (str): Name of a PyMOL molecule object.
226 ChainName (str): Name of a chain in a molecule.
227 SortBy (str): Sort ligand names alphabetically or by size. Possible
228 values: Alphabetical or Size
229 SortOrder (str): Sort order for sorting ligands. Possible values:
230 Ascending, Descending, Auto. The 'Auto' value implies automatic
231 determination of sort order based on the value of 'SortBy'.
232 Automatic defaults: Descending for SortBy value of Size; Ascending
233 for SortBy value of Alphabetical.
234 IgnoreHydrogens (str): Ignore hydrogens during determination of ligand
235 size.
236
237 Returns:
238 list: Names of ligands present in chain for a molecule sorted by size
239 or alphabetically.
240
241 """
242 if not (len(MoleculeName) and len(ChainName)):
243 return None
244
245 LigandsInfoMap = _GetLigandsInfo(MoleculeName, ChainName, SortBy, SortOrder, IgnoreHydrogens)
246
247 LigandIDs = LigandsInfoMap["LigandResNames"]
248 if not len(LigandIDs):
249 LigandIDs = None
250
251 return LigandIDs
252
253
254 def GetLargestLigand(MoleculeName, ChainName, IgnoreHydrogens="Yes"):
255 """Get name of the largest ligand for a chain present in a molecule. Ligands
256 are identified using PyMOL 'organic' selection.
257
258 Arguments:
259 MoleculeName (str): Name of a PyMOL molecule object.
260 ChainName (str): Name of a chain in a molecule.
261 IgnoreHydrogens (str): Ignore hydrogens during determination of ligand
262 size.
263
264 Returns:
265 str: Name of the largest ligand present in a chain.
266
267 """
268 if not (len(MoleculeName) and len(ChainName)):
269 return None
270
271 SortBy = "Size"
272 SortOrder = "Descending"
273 LigandsInfoMap = _GetLigandsInfo(MoleculeName, ChainName, SortBy, SortOrder, IgnoreHydrogens)
274 LigandIDs = LigandsInfoMap["LigandResNames"]
275
276 if len(LigandIDs):
277 LigandID = LigandIDs[0]
278 else:
279 LigandID = None
280
281 return LigandID
282
283
284 def _GetChainsAndLigands(MoleculeName, LigandSortBy="Size", LigandSortOrder="Auto", LigandIgnoreHydrogens="Yes"):
285 """Get chain identifiers in a molecule along with names of the ligands
286 present in chains. Ligands are identified using PyMOL 'organic' selection.
287 """
288 if not len(MoleculeName):
289 return None
290
291 ChainIDs = GetChains(MoleculeName)
292 if ChainIDs is None:
293 return None
294
295 ChainsAndLigandsMap = {}
296 ChainsAndLigandsMap["ChainIDs"] = []
297 ChainsAndLigandsMap["LigandIDs"] = {}
298
299 for ChainID in ChainIDs:
300 ChainsAndLigandsMap["ChainIDs"].append(ChainID)
301 ChainsAndLigandsMap["LigandIDs"][ChainID] = []
302
303 LigandIDs = GetLigands(
304 MoleculeName, ChainID, SortBy=LigandSortBy, SortOrder=LigandSortOrder, IgnoreHydrogens=LigandIgnoreHydrogens
305 )
306 if LigandIDs is not None:
307 ChainsAndLigandsMap["LigandIDs"][ChainID] = LigandIDs
308
309 return ChainsAndLigandsMap
310
311
312 def _GetLigandsInfo(MoleculeName, ChainName, SortBy="Size", SortOrder="Auto", IgnoreHydrogens="Yes"):
313 """Retrieve information about ligands present in a chain of a molecule."""
314
315 if not MiscUtil.CheckTextValue(SortBy, "Size Alphabetical"):
316 MiscUtil.PrintError(
317 "PyMOLUtil._GetLigandsInfo: The value specified, %s, for parameter SortBy is not valid. SupportedValues: Size Alphabetical"
318 % SortBy
319 )
320
321 if not MiscUtil.CheckTextValue(SortOrder, "Ascending Descending Auto"):
322 MiscUtil.PrintError(
323 "PyMOLUtil._GetLigandsInfo: The value specified, %s, for parameter SortOrder is not valid. SupportedValues: Ascending Descending Auto"
324 % SortOrder
325 )
326
327 if not MiscUtil.CheckTextValue(IgnoreHydrogens, "Yes No"):
328 MiscUtil.PrintError(
329 "PyMOLUtil._GetLigandsInfo: The value specified, %s, for parameter IgnoreHydrogens is not valid. SupportedValues: Yes No"
330 % IgnoreHydrogens
331 )
332
333 SortBySize = True if re.match("^Size$", SortBy, re.I) else False
334 if re.match("^Auto$", SortOrder, re.I):
335 SortOrderDescending = True if re.match("^Size$", SortBy, re.I) else False
336 else:
337 SortOrderDescending = True if re.match("^Descending$", SortOrder, re.I) else False
338 IgnoreHydrogenAtoms = True if re.match("^Yes$", IgnoreHydrogens, re.I) else False
339
340 # Set up a command to retrieve all appropriate ligand atoms in organic ligands...
341 SelectionCmd = "%s and chain %s and organic" % (MoleculeName, ChainName)
342 if IgnoreHydrogenAtoms:
343 SelectionCmd = "%s and not hydro" % (SelectionCmd)
344
345 # Retrieve atoms...
346 stored.LigandsInfo = []
347 cmd.iterate(SelectionCmd, "stored.LigandsInfo.append([resi, resn])")
348
349 # Retrieve ligands...
350 LigandsInfoMap = {}
351 LigandsInfoMap["LigandResNames"] = []
352 LigandsInfoMap["LigandAtomCount"] = {}
353 LigandsInfoMap["LigandResNumber"] = {}
354
355 for LigandResNum, LigandResName in stored.LigandsInfo:
356 if LigandResName in LigandsInfoMap["LigandResNames"]:
357 LigandsInfoMap["LigandAtomCount"][LigandResName] += 1
358 else:
359 LigandsInfoMap["LigandResNames"].append(LigandResName)
360 LigandsInfoMap["LigandAtomCount"][LigandResName] = 1
361 LigandsInfoMap["LigandResNumber"][LigandResName] = LigandResNum
362
363 if not len(LigandsInfoMap["LigandResNames"]):
364 return LigandsInfoMap
365
366 # Sort ligand names...
367 ReverseOrder = True if SortOrderDescending else False
368 if SortBySize:
369 SortedLigandResNames = sorted(
370 LigandsInfoMap["LigandResNames"],
371 key=lambda LigandResName: LigandsInfoMap["LigandAtomCount"][LigandResName],
372 reverse=ReverseOrder,
373 )
374 else:
375 # Sort alphabetically...
376 SortedLigandResNames = sorted(LigandsInfoMap["LigandResNames"], reverse=ReverseOrder)
377
378 LigandsInfoMap["LigandResNames"] = SortedLigandResNames
379
380 return LigandsInfoMap
381
382
383 def GetCentroid(Selection):
384 """Get centroid of a PyMOL selection.
385
386 Arguments:
387 MoleculeName (str): Name of a PyMOL selection.
388
389 Returns:
390 list or None: List of centroid values.
391
392 """
393
394 SelectionCmd = "(%s)" % Selection
395
396 stored.CoordinatesInfo = []
397 cmd.iterate_state(1, SelectionCmd, "stored.CoordinatesInfo.append([x, y, z])")
398
399 XCoords = [Coords[0] for Coords in stored.CoordinatesInfo]
400 YCoords = [Coords[1] for Coords in stored.CoordinatesInfo]
401 ZCoords = [Coords[2] for Coords in stored.CoordinatesInfo]
402
403 NumOfCoords = len(stored.CoordinatesInfo)
404
405 CentroidX = sum(XCoords) / NumOfCoords
406 CentroidY = sum(YCoords) / NumOfCoords
407 CentroidZ = sum(ZCoords) / NumOfCoords
408
409 return [CentroidX, CentroidY, CentroidZ]
410
411
412 def AreAminoAcidResiduesPresent(MoleculeName, ChainName, Type="Any"):
413 """Check for the presence of amino acid residues in a chain of a
414 molecule. Chains are identified using PyMOL 'polymer' selection.
415 Nonstandard amino acid residues correspond to all residues other than
416 the standard amino acids and nucleic acids. Any amino acid residues cover
417 all residues other than the standard nucleic acids.
418
419 Arguments:
420 MoleculeName (str): Name of a PyMOL molecule object.
421 ChainName (str): Name of a chain in a molecule.
422 Type (str): Types of amino acids: Standard, NonStandard, Any
423
424 Returns:
425 boolean: True or False.
426
427 """
428
429 if not (len(MoleculeName) and len(ChainName)):
430 return False
431
432 if not re.match("^(Standard|NonStandard|Any)$", Type, re.I):
433 MiscUtil.PrintError("PyMOLUtil.AreAminoAcidResiduesPresent: Invalid amino acid type: %s" % Type)
434
435 SelectionCmd = _SetupAminoAcidResiduesSelectionCmd(MoleculeName, ChainName, Type)
436
437 Status = True if cmd.count_atoms(SelectionCmd) else False
438
439 return Status
440
441
442 def AreNucleicAcidResiduesPresent(MoleculeName, ChainName):
443 """Check for the presence of nucleic acid residues in a chain of a
444 molecule. Chains are identified using PyMOL 'polymer' selection.
445
446 Arguments:
447 MoleculeName (str): Name of a PyMOL molecule object.
448 ChainName (str): Name of a chain in a molecule.
449
450 Returns:
451 boolean: True or False.
452
453 """
454
455 if not (len(MoleculeName) and len(ChainName)):
456 return False
457
458 ResidueNames = _GetNucleicAcidResidueNames()
459 if not len(ResidueNames):
460 return False
461
462 ResidueNamesSelection = "+".join(ResidueNames)
463 SelectionCmd = "(%s and chain %s and polymer and (resn %s))" % (MoleculeName, ChainName, ResidueNamesSelection)
464
465 Status = True if cmd.count_atoms(SelectionCmd) else False
466
467 return Status
468
469
470 def _SetupAminoAcidResiduesSelectionCmd(MoleculeName, ChainName, Type):
471 """Set up amino acids selection command for PyMOL."""
472
473 AminoAcidsSelection = "+".join(_GetAminoAcidResidueNames())
474 NucleicAcidsSelection = "+".join(_GetNucleicAcidResidueNames())
475
476 if re.match("^Standard$", Type, re.I):
477 SelectionCmd = "(%s and chain %s and polymer and (resn %s))" % (MoleculeName, ChainName, AminoAcidsSelection)
478 elif re.match("^NonStandard$", Type, re.I):
479 SelectionCmd = "(%s and chain %s and polymer and (not ((resn %s) or (resn %s))))" % (
480 MoleculeName,
481 ChainName,
482 AminoAcidsSelection,
483 NucleicAcidsSelection,
484 )
485 else:
486 # Any amino acid resiudes...
487 SelectionCmd = "(%s and chain %s and polymer and (not (resn %s)))" % (
488 MoleculeName,
489 ChainName,
490 NucleicAcidsSelection,
491 )
492
493 return SelectionCmd
494
495
496 def _GetAminoAcidResidueNames():
497 """Get list of amino acid residue names."""
498
499 ResidueNames = [
500 "ALA",
501 "ARG",
502 "ASN",
503 "ASP",
504 "CYS",
505 "GLN",
506 "GLU",
507 "GLY",
508 "HIS",
509 "ILE",
510 "LEU",
511 "LYS",
512 "MET",
513 "PHE",
514 "PRO",
515 "SER",
516 "THR",
517 "TRP",
518 "TYR",
519 "VAL",
520 ]
521
522 return ResidueNames
523
524
525 def _GetNucleicAcidResidueNames():
526 """Get list of nucleic acid residue names."""
527
528 ResidueNames = ["A", "G", "T", "U", "C", "DA", "DG", "DT", "DU", "DC"]
529
530 return ResidueNames
531
532
533 def GetPolymerResiduesInfo(MoleculeName, ChainName):
534 """Get information for residues present in a chain of a molecule.
535 Chains are identified using PyMOL 'polymer' selection.
536
537 Arguments:
538 MoleculeName (str): Name of a PyMOL molecule object.
539 ChainName (str): Name of a chain in a molecule.
540
541 Returns:
542 dict: A dictionary containing list of residue names and dictionaries of
543 residue numbers and residue count for each residue. Names of
544 residues in the dictionary are not sorted.
545
546 Examples:
547
548 ResiduesInfo = GetPolymerResiduesInfo(MolName, ChainName)
549 for ResName in ResiduesInfo["ResNames"]:
550 ResCount = ResiduesInfo["ResCount"][ResName]
551 ResNums = ResiduesInfo["ResNum"][ResName]
552 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
553 (ResName, ResCount, ResNums))
554
555 """
556 if not (len(MoleculeName) and len(ChainName)):
557 return None
558
559 SelectionCmd = "%s and chain %s and polymer" % (MoleculeName, ChainName)
560 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
561
562 return ResiduesInfoMap
563
564
565 def GetAminoAcidResiduesInfo(MoleculeName, ChainName, Type="Standard"):
566 """Get information for amino acid residues present in a chain of a
567 molecule. Chains are identified using PyMOL 'polymer' selection.
568 Nonstandard amino acid residues correspond to all residues other than
569 the standard amino acids and nucleic acids. Any amino acid residues cover
570 all residues other than the standard nucleic acids.
571
572 Arguments:
573 MoleculeName (str): Name of a PyMOL molecule object.
574 ChainName (str): Name of a chain in a molecule.
575 Type (str): Types of amino acids: Standard, NonStandard, Any
576
577 Returns:
578 dict: A dictionary containing list of residue names and dictionaries of
579 residue numbers and residue count for each residue. Names of
580 residues in the dictionary are not sorted.
581
582 Examples:
583
584 ResiduesInfo = GetPolymerResiduesInfo(MolName, ChainName)
585 for ResName in ResiduesInfo["ResNames"]:
586 ResCount = ResiduesInfo["ResCount"][ResName]
587 ResNums = ResiduesInfo["ResNum"][ResName]
588 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
589 (ResName, ResCount, ResNums))
590
591 """
592
593 if not (len(MoleculeName) and len(ChainName)):
594 return None
595
596 if not re.match("^(Standard|NonStandard|Any)$", Type, re.I):
597 MiscUtil.PrintError("PyMOLUtil.GetAminoAcidResiduesInfo: Invalid amino acid type: %s" % Type)
598
599 SelectionCmd = _SetupAminoAcidResiduesSelectionCmd(MoleculeName, ChainName, Type)
600 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
601
602 return ResiduesInfoMap
603
604
605 def GetNucleicAcidResiduesInfo(MoleculeName, ChainName):
606 """Get information for nucleic acid residues present in a chain of
607 a molecule. Chains are identified using PyMOL 'polymer' selection.
608
609 Arguments:
610 MoleculeName (str): Name of a PyMOL molecule object.
611 ChainName (str): Name of a chain in a molecule.
612
613 Returns:
614 dict: A dictionary containing list of residue names and dictionaries of
615 residue numbers and residue count for each residue. Names of
616 residues in the dictionary are not sorted.
617
618 Examples:
619
620 ResiduesInfo = GetPolymerResiduesInfo(MolName, ChainName)
621 for ResName in ResiduesInfo["ResNames"]:
622 ResCount = ResiduesInfo["ResCount"][ResName]
623 ResNums = ResiduesInfo["ResNum"][ResName]
624 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
625 (ResName, ResCount, ResNums))
626
627 """
628
629 if not (len(MoleculeName) and len(ChainName)):
630 return None
631
632 ResidueNames = _GetNucleicAcidResidueNames()
633
634 ResidueNamesSelection = "+".join(ResidueNames)
635 SelectionCmd = "(%s and chain %s and polymer and (resn %s))" % (MoleculeName, ChainName, ResidueNamesSelection)
636
637 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
638
639 return ResiduesInfoMap
640
641
642 def GetSelectionResiduesInfo(SelectionCmd):
643 """Get information for residues in a chain specified by a selection command.
644
645 Arguments:
646 SelectionCmd (str): PyMOL selection command.
647
648 Returns:
649 dict: A dictionary containing list of residue names and dictionaries of
650 residue numbers and residue count for each residue. Names of
651 residues in the dictionary are not sorted.
652
653 Examples:
654
655 ResiduesInfo = GetSelectionResiduesInfo(SelectionCmd)
656 for ResName in ResiduesInfo["ResNames"]:
657 ResCount = ResiduesInfo["ResCount"][ResName]
658 ResNums = ResiduesInfo["ResNum"][ResName]
659 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
660 (ResName, ResCount, ResNums))
661
662 """
663 if not len(SelectionCmd):
664 return None
665
666 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
667
668 return ResiduesInfoMap
669
670
671 def GetSolventResiduesInfo(MoleculeName, ChainName):
672 """Get information for solvent residues present in a chain of a molecule.
673 Solvents are identified using PyMOL 'solvent' selection.
674
675 Arguments:
676 MoleculeName (str): Name of a PyMOL molecule object.
677 ChainName (str): Name of a chain in a molecule.
678
679 Returns:
680 dict: A dictionary containing list of residue names and dictionaries of
681 residue numbers and residue count for each residue. Names of
682 residues in the dictionary are not sorted.
683
684 Examples:
685
686 ResiduesInfo = GetSolventResiduesInfo(MolName, ChainName)
687 for ResName in ResiduesInfo["ResNames"]:
688 ResCount = ResiduesInfo["ResCount"][ResName]
689 ResNums = ResiduesInfo["ResNum"][ResName]
690 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
691 (ResName, ResCount, ResNums))
692
693 """
694 if not (len(MoleculeName) and len(ChainName)):
695 return None
696
697 SelectionCmd = "%s and chain %s and solvent" % (MoleculeName, ChainName)
698 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
699
700 return ResiduesInfoMap
701
702
703 def GetInorganicResiduesInfo(MoleculeName, ChainName):
704 """Get information for inorganic residues present in a chain of a molecule.
705 Inorganic residues are identified using PyMOL 'inorganic' selection.
706
707 Arguments:
708 MoleculeName (str): Name of a PyMOL molecule object.
709 ChainName (str): Name of a chain in a molecule.
710
711 Returns:
712 dict: A dictionary containing list of residue names and dictionaries of
713 residue numbers and residue count for each residue. Names of
714 residues in the dictionary are not sorted.
715
716 Examples:
717
718 ResiduesInfo = GetInorganicResiduesInfo(MolName, ChainName)
719 for ResName in ResiduesInfo["ResNames"]:
720 ResCount = ResiduesInfo["ResCount"][ResName]
721 ResNums = ResiduesInfo["ResNum"][ResName]
722 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
723 (ResName, ResCount, ResNums))
724
725 """
726 if not (len(MoleculeName) and len(ChainName)):
727 return None
728
729 SelectionCmd = "%s and chain %s and inorganic" % (MoleculeName, ChainName)
730 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
731
732 return ResiduesInfoMap
733
734
735 def GetLigandResiduesInfo(MoleculeName, ChainName):
736 """Get information for ligand residues present in a chain of a molecule.
737 Ligands are identified using PyMOL 'organic' selection.
738
739 Arguments:
740 MoleculeName (str): Name of a PyMOL molecule object.
741 ChainName (str): Name of a chain in a molecule.
742
743 Returns:
744 dict: A dictionary containing list of residue names and dictionaries of
745 residue numbers and residue count for each residue. Names of
746 residues in the dictionary are not sorted.
747
748 Examples:
749
750 ResiduesInfo = GetLigandResiduesInfo(MolName, ChainName)
751 for ResName in ResiduesInfo["ResNames"]:
752 ResCount = ResiduesInfo["ResCount"][ResName]
753 ResNums = ResiduesInfo["ResNum"][ResName]
754 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
755 (ResName, ResCount, ResNums))
756
757 """
758 if not (len(MoleculeName) and len(ChainName)):
759 return None
760
761 SelectionCmd = "%s and chain %s and organic" % (MoleculeName, ChainName)
762 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
763
764 return ResiduesInfoMap
765
766
767 def GetPocketPolymerResiduesInfo(MoleculeName, ChainName, LigandResName, LigandResNum, PocketDistanceCutoff):
768 """Get information for chain residues present in a pocket around a ligand
769 in a molecule. Polymer residues are identified using negation of PyMOL
770 selection operators 'organic', 'solvent', and 'inorganic'.
771
772 Arguments:
773 MoleculeName (str): Name of a PyMOL molecule object.
774 ChainName (str): Name of a chain in a molecule.
775 LigandResName (str): Residue name of a ligand in a chain.
776 LigandResNum (str): Residue number of a ligand in a chain.
777 PocketDistanceCutoff (float): Distance around ligand to identify pocket
778 residues.
779
780 Returns:
781 dict: A dictionary containing list of residue names and dictionaries of
782 residue numbers and residue count for each residue. Names of
783 residues in the dictionary are not sorted.
784
785 Examples:
786
787 ResiduesInfo = GetPocketPolymerResiduesInfo(MolName, ChainName)
788 for ResName in ResiduesInfo["ResNames"]:
789 ResCount = ResiduesInfo["ResCount"][ResName]
790 ResNums = ResiduesInfo["ResNum"][ResName]
791 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
792 (ResName, ResCount, ResNums))
793
794 """
795 if not (len(MoleculeName) and len(ChainName) and len(LigandResName) and len(LigandResNum)):
796 return None
797
798 LigandSelection = "%s and chain %s and organic and resn %s and resi %s" % (
799 MoleculeName,
800 ChainName,
801 LigandResName,
802 LigandResNum,
803 )
804 MoleculeSelection = "%s and chain %s" % (MoleculeName, ChainName)
805 SelectionCmd = "((byresidue (%s) within %.1f of (%s)) and (not solvent) and (not inorganic) and (not organic))" % (
806 MoleculeSelection,
807 PocketDistanceCutoff,
808 LigandSelection,
809 )
810
811 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
812
813 return ResiduesInfoMap
814
815
816 def GetPocketSolventResiduesInfo(MoleculeName, ChainName, LigandResName, LigandResNum, PocketDistanceCutoff):
817 """Get information for solvent residues present in a pocket around a ligand
818 in a molecule. Solvent residues are identified using PyMOL 'solvent'
819 selection.
820
821 Arguments:
822 MoleculeName (str): Name of a PyMOL molecule object.
823 ChainName (str): Name of a chain in a molecule.
824 LigandResName (str): Residue name of a ligand in a chain.
825 LigandResNum (str): Residue number of a ligand in a chain.
826 PocketDistanceCutoff (float): Distance around ligand to identify pocket
827 residues.
828
829 Returns:
830 dict: A dictionary containing list of residue names and dictionaries of
831 residue numbers and residue count for each residue. Names of
832 residues in the dictionary are not sorted.
833
834 Examples:
835
836 ResiduesInfo = GetPocketSolventResiduesInfo(MolName, ChainName)
837 for ResName in ResiduesInfo["ResNames"]:
838 ResCount = ResiduesInfo["ResCount"][ResName]
839 ResNums = ResiduesInfo["ResNum"][ResName]
840 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
841 (ResName, ResCount, ResNums))
842
843 """
844 if not (len(MoleculeName) and len(ChainName) and len(LigandResName) and len(LigandResNum)):
845 return None
846
847 LigandSelection = "%s and chain %s and organic and resn %s and resi %s" % (
848 MoleculeName,
849 ChainName,
850 LigandResName,
851 LigandResNum,
852 )
853 MoleculeSelection = "%s and chain %s" % (MoleculeName, ChainName)
854 SelectionCmd = "((byresidue (%s) within %.1f of (%s)) and solvent)" % (
855 MoleculeSelection,
856 PocketDistanceCutoff,
857 LigandSelection,
858 )
859
860 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
861
862 return ResiduesInfoMap
863
864
865 def GetPocketInorganicResiduesInfo(MoleculeName, ChainName, LigandResName, LigandResNum, PocketDistanceCutoff):
866 """Get information for inorganic residues present in a pocket around a
867 ligand in a molecule. Inorganic residues are identified using PyMOL
868 'inorganic' selection.
869
870 Arguments:
871 MoleculeName (str): Name of a PyMOL molecule object.
872 ChainName (str): Name of a chain in a molecule.
873 LigandResName (str): Residue name of a ligand in a chain.
874 LigandResNum (str): Residue number of a ligand in a chain.
875 PocketDistanceCutoff (float): Distance around a ligand to identify
876 pocket residues.
877
878 Returns:
879 dict: A dictionary containing list of residue names and dictionaries of
880 residue numbers and residue count for each residue. Names of
881 residues in the dictionary are not sorted.
882
883 Examples:
884
885 ResiduesInfo = GetPocketInorganicResiduesInfo(MolName, ChainName)
886 for ResName in ResiduesInfo["ResNames"]:
887 ResCount = ResiduesInfo["ResCount"][ResName]
888 ResNums = ResiduesInfo["ResNum"][ResName]
889 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
890 (ResName, ResCount, ResNums))
891
892 """
893 if not (len(MoleculeName) and len(ChainName) and len(LigandResName) and len(LigandResNum)):
894 return None
895
896 LigandSelection = "%s and chain %s and organic and resn %s and resi %s" % (
897 MoleculeName,
898 ChainName,
899 LigandResName,
900 LigandResNum,
901 )
902 MoleculeSelection = "%s and chain %s" % (MoleculeName, ChainName)
903 SelectionCmd = "((byresidue (%s) within %.1f of (%s)) and inorganic)" % (
904 MoleculeSelection,
905 PocketDistanceCutoff,
906 LigandSelection,
907 )
908
909 ResiduesInfoMap = _GetSelectionResiduesInfo(SelectionCmd)
910
911 return ResiduesInfoMap
912
913
914 def GetPhiPsiResiduesInfo(MoleculeName, ChainName, Categorize=True):
915 """Get phi and psi torsion angle information for residues in a chain of a
916 molecule containing amino acids.
917
918 The phi and psi angles are optionally categorized into the following groups
919 corresponding to four types of Ramachandran plots:
920
921 General: All residues except glycine, proline, or pre-proline
922 Glycine: Only glycine residues
923 Proline: Only proline residues
924 Pre-Proline: Only residues before proline not including glycine or proline
925
926 Arguments:
927 MoleculeName (str): Name of a PyMOL molecule object.
928 ChainName (str): Name of a chain in a molecule.
929
930 Returns:
931 dict: A dictionary containing sorted list of residue numbers and
932 dictionaries of residue names, phi and psi angles for each residue
933 number.
934
935 Examples:
936
937 PhiPsiInfoMap = GetPhiPsiResiduesInfo(MolName, ChainName, True)
938 for ResNum in PhiPsiInfoMap["ResNums"]:
939 ResName = PhiPsiInfoMap["ResName"][ResNum]
940 Phi = PhiPsiInfoMap["Phi"][ResNum]
941 Psi = PhiPsiInfoMap["Psi"][ResNum]
942 Category = PhiPsiInfoMap["Category"][ResNum]
943 MiscUtil.PrintInfo("ResNum: %s; ResName: %s; Phi: %8.2f;
944 Psi: %8.2f; Category: %s" % (ResNum, ResName, Phi, Psi,
945 Categorize))
946
947 """
948 if not (len(MoleculeName) and len(ChainName)):
949 return None
950
951 SelectionCmd = "%s and chain %s" % (MoleculeName, ChainName)
952 PhiPsiResiduesInfoMap = _GetSelectionPhiPsiResiduesInfo(SelectionCmd, Categorize)
953
954 return PhiPsiResiduesInfoMap
955
956
957 def GetPhiPsiChainsAndResiduesInfo(MoleculeName, Categorize=True):
958 """Get phi and psi torsion angle information for residues across chains in
959 a molecule containing amino acids.
960
961 The phi and psi angles are optionally categorized into the following groups
962 corresponding to four types of Ramachandran plots:
963
964 General: All residues except glycine, proline, or pre-proline
965 Glycine: Only glycine residues
966 Proline: Only proline residues
967 Pre-Proline: Only residues before proline not including glycine or proline
968
969 Arguments:
970 MoleculeName (str): Name of a PyMOL molecule object.
971
972 Returns:
973 dict: A dictionary containing sorted list of residue numbers for each
974 chain and dictionaries of residue names, phi and psi angles for each
975 residue number.
976
977 Examples:
978
979 PhiPsiInfoMap = GetPhiPsiChainsAndResiduesInfo(MolName)
980 for ChainID in PhiPsiInfoMap["ChainIDs"]:
981 for ResNum in PhiPsiInfoMap["ResNums"][ChainID]:
982 ResName = PhiPsiInfoMap["ResName"][ChainID][ResNum]
983 Phi = PhiPsiInfoMap["Phi"][ChainID][ResNum]
984 Psi = PhiPsiInfoMap["Psi"][ChainID][ResNum]
985 Category = PhiPsiInfoMap["Category"][ChainID][ResNum]
986 MiscUtil.PrintInfo("ChainID: %s; ResNum: %s; ResName: %s; Phi: %8.2f;
987 Psi: %8.2f; Category: %s" % (ChainID, ResNum, ResName, Phi,
988 Psi, Category))
989
990 """
991 if not len(MoleculeName):
992 return None
993
994 SelectionCmd = "%s" % (MoleculeName)
995 PhiPsiResiduesInfoMap = _GetSelectionPhiPsiChainsAndResiduesInfo(SelectionCmd, Categorize)
996
997 return PhiPsiResiduesInfoMap
998
999
1000 def GetPhiPsiCategoriesResiduesInfo(MoleculeName, ChainName):
1001 """Get phi and psi torsion angle information for residues in a chain of a
1002 molecule containing amino acids.
1003
1004 The phi and psi angles are optionally categorized into the following groups
1005 corresponding to four types of Ramachandran plots:
1006
1007 General: All residues except glycine, proline, or pre-proline
1008 Glycine: Only glycine residues
1009 Proline: Only proline residues
1010 Pre-Proline: Only residues before proline not including glycine or proline
1011
1012 Arguments:
1013 MoleculeName (str): Name of a PyMOL molecule object.
1014 ChainName (str): Name of a chain in a molecule.
1015
1016 Returns:
1017 dict1: Phi and psi angle information for residues in General category.
1018 It's a dictionary containing sorted list of residue numbers and
1019 dictionaries of residue names, phi and psi angles for each residue
1020 number.
1021 dict2: Phi and psi angle information for residues in Gly category.
1022 dict3: Phi and psi angle information for residues in Pro category.
1023 dict2: Phi and psi angle information for residues in Pre-Pro category.
1024
1025 Examples:
1026
1027 GeneralPhiPsiInfo, GlyPhiPsiInfo, ProPhiPsiInfo, PreProPhiPsiInfo =
1028 GetPhiPsiCategoriesResiduesInfo(MolName, ChainID)
1029 for ResNum in GeneralPhiPsiInfo["ResNums"]:
1030 ResName = GeneralPhiPsiInfo["ResName"][ResNum]
1031 Phi = GeneralPhiPsiInfo["Phi"][ResNum]
1032 Psi = GeneralPhiPsiInfo["Psi"][ResNum]
1033 MiscUtil.PrintInfo("ResNum: %s; ResName: %s;
1034 Phi: %8.2f; Psi: %8.2f" % (ResNum, ResName, Phi, Psi))
1035
1036 """
1037 if not (len(MoleculeName) and len(ChainName)):
1038 return None
1039
1040 SelectionCmd = "%s and chain %s" % (MoleculeName, ChainName)
1041 GeneralPhiPsiInfo, GlyPhiPsiInfo, ProPhiPsiInfo, PreProPhiPsiInfo = _GetSelectionPhiPsiCategoriesResiduesInfo(
1042 SelectionCmd
1043 )
1044
1045 return GeneralPhiPsiInfo, GlyPhiPsiInfo, ProPhiPsiInfo, PreProPhiPsiInfo
1046
1047
1048 def GetSurfaceAndBuriedResiduesInfo(MoleculeName, ChainName, SASACutoff=2.5):
1049 """Get information for surafce and buried residues present in a chain of a
1050 molecule. The surface residues correspond to residues with Solvent Accessible
1051 Surface Area (SASA) greater than or equal to the cutoff value. Otherwise, these
1052 residues are considered as buried residues.
1053
1054 Arguments:
1055 MoleculeName (str): Name of a PyMOL molecule object.
1056 ChainName (str): Name of a chain in a molecule.
1057 SASACutoff (float): SASA cutoff for heavy atoms corresponding to
1058 surface residues in chain. Units: Angstroms ** 2
1059
1060 Returns:
1061 dict: A dictionary containing list of residue names and dictionaries of
1062 residue numbers and residue count for each residue. Names of
1063 residues in the dictionary are not sorted.
1064 dict2: Buried residues in a chain.
1065
1066 Examples:
1067
1068 SurfaceResiduesInfo, BurriedResiduesInfo =
1069 GetSurfaceAndBuriedResiduesInfo(MolName, ChainName, 2.5)
1070 for ResName in SurfaceResiduesInfo["ResNames"]:
1071 ResCount = ResiduesInfo["ResCount"][ResName]
1072 ResNums = ResiduesInfo["ResNum"][ResName]
1073 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
1074 (ResName, ResCount, ResNums))
1075
1076 """
1077 if not (len(MoleculeName) and len(ChainName)):
1078 return None
1079
1080 # Get ready to calculate solvent accessible surface area..
1081 CurrentDotSolvent = cmd.get("dot_solvent")
1082 cmd.set("dot_solvent", 1)
1083
1084 # Setup tmp object name...
1085 TmpChainName = "Tmp_%s" % (MoleculeName)
1086 TmpChainSelection = "(%s and chain %s and polymer and not hydrogens)" % (MoleculeName, ChainName)
1087 cmd.create(TmpChainName, "(%s)" % (TmpChainSelection))
1088
1089 # Calculate SASA for chain and load it into b...
1090 cmd.get_area(TmpChainName, load_b=1)
1091
1092 # Retrieve SASA for residues as B values...
1093 ResiduesBValuesInfoMap = _GetSelectionResiduesBValuesInfo(TmpChainName)
1094
1095 # Retrieve information for surface and buried residues...
1096 SurfaceResiduesInfoMap = _GetResiduesInfoFromResiduesBValues(ResiduesBValuesInfoMap, ">=", SASACutoff)
1097 BuriedResiduesInfoMap = _GetResiduesInfoFromResiduesBValues(ResiduesBValuesInfoMap, "<", SASACutoff)
1098
1099 # Delete tmp objects...
1100 cmd.delete(TmpChainName)
1101
1102 # Restore current dot solvent...
1103 cmd.set("dot_solvent", CurrentDotSolvent)
1104
1105 return SurfaceResiduesInfoMap, BuriedResiduesInfoMap
1106
1107
1108 def GetInterfaceChainsResiduesByCAlphaAtomsDistance(
1109 MoleculeName1, ChainNames1, MoleculeName2, ChainNames2, DistanceCutoff=8.0
1110 ):
1111 """Get information for interface residues between chains in two
1112 molecules based on the distance between CAlpha atoms. The chain
1113 specification for molecules may contain multiple chain names delimited
1114 by commas.
1115
1116 The interface residues are identified using PyMOL 'bycalpha' selection
1117 operator with in a specified distance.
1118
1119 Arguments:
1120 MoleculeName1 (str): Name of a PyMOL molecule object.
1121 ChainNames1 (str): A chain name or comma delimited list of chain
1122 names in a molecule.
1123 MoleculeName2 (str): Name of a PyMOL molecule object.
1124 ChainNames2 (str): A chain name or comma delimited list of chain
1125 names in a molecule.
1126 DistanceCutoff (float): Distance cutoff for distance between
1127 any two CAlpha atoms in interface residues in different chains.
1128
1129 Returns:
1130 dict1: Interface residues in a chain for first molecule. It is a
1131 dictionary containing list of residue names and dictionaries of
1132 residue numbers and residue count for each residue. Names of
1133 residues in the dictionary are not sorted.
1134 dict2: Interface residues in the chain for second molecule.
1135
1136 Examples:
1137
1138 ResiduesInfo1, ResiduesInfo2 =
1139 GetInterfaceResiduesByHeavyAtomsDistance(MolName1,
1140 ChainName1, MolName2, ChainName2, DistanceCutoff)
1141 for ChainID in ResiduesInfo1["ChainIDs"]:
1142 for ResName in ResiduesInfo1["ResNames"][ChainID]:
1143 ResCount = ResiduesInfo1["ResCount"][ChainID][ResName]
1144 ResNums = ResiduesInfo1["ResNum"][ChainID][ResName]
1145 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums:
1146 %s" % (ResName, ResCount, ResNums))
1147
1148 """
1149 ChainNames1Selection, ChainNames2Selection = _ValidateAndSetupChainSelectionsForInterfaceResidues(
1150 MoleculeName1, ChainNames1, MoleculeName2, ChainNames2
1151 )
1152
1153 if ChainNames1Selection is None or ChainNames2Selection is None:
1154 return None
1155
1156 MoleculeSelection1 = "%s and chain %s" % (MoleculeName1, ChainNames1Selection)
1157 MoleculeSelection2 = "%s and chain %s" % (MoleculeName2, ChainNames2Selection)
1158
1159 SelectionCmd1 = "((bycalpha (%s) within %.1f of (%s)) and polymer)" % (
1160 MoleculeSelection1,
1161 DistanceCutoff,
1162 MoleculeSelection2,
1163 )
1164 ResiduesInfoMap1 = _GetSelectionChainsAndResiduesInfo(SelectionCmd1)
1165
1166 SelectionCmd2 = "((bycalpha (%s) within %.1f of (%s)) and polymer)" % (
1167 MoleculeSelection2,
1168 DistanceCutoff,
1169 MoleculeSelection1,
1170 )
1171 ResiduesInfoMap2 = _GetSelectionChainsAndResiduesInfo(SelectionCmd2)
1172
1173 return ResiduesInfoMap1, ResiduesInfoMap2
1174
1175
1176 def GetInterfaceChainsResiduesByHeavyAtomsDistance(
1177 MoleculeName1, ChainNames1, MoleculeName2, ChainNames2, DistanceCutoff=5.0
1178 ):
1179 """Get information for interface residues between chains in two
1180 molecules based on the distance between heavy atoms. The chain
1181 specification for molecules may contain multiple chain names delimited
1182 by commas.
1183
1184 The interface residues are identified using PyMOL 'byresidue' selection
1185 operator with in a specified distance.
1186
1187 Arguments:
1188 MoleculeName1 (str): Name of a PyMOL molecule object.
1189 ChainNames1 (str): A chain name or comma delimited list of chain
1190 names in a molecule.
1191 MoleculeName2 (str): Name of a PyMOL molecule object.
1192 ChainNames2 (str): A chain name or comma delimited list of chain
1193 names in a molecule.
1194 DistanceCutoff (float): Distance cutoff for distance between
1195 any two heavy atoms in interface residues in different chains.
1196
1197 Returns:
1198 dict1: Interface residues in a chain for first molecule. It is a
1199 dictionary containing list of residue names and dictionaries of
1200 residue numbers and residue count for each residue. Names of
1201 residues in the dictionary are not sorted.
1202 dict2: Interface residues in the chain for second molecule.
1203
1204 Examples:
1205
1206 ResiduesInfo1, ResiduesInfo2 =
1207 GetInterfaceResiduesByHeavyAtomsDistance(MolName1,
1208 ChainName1, MolName2, ChainName2, DistanceCutoff)
1209 for ChainID in ResiduesInfo1["ChainIDs"]:
1210 for ResName in ResiduesInfo1["ResNames"][ChainID]:
1211 ResCount = ResiduesInfo1["ResCount"][ChainID][ResName]
1212 ResNums = ResiduesInfo1["ResNum"][ChainID][ResName]
1213 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums:
1214 %s" % (ResName, ResCount, ResNums))
1215
1216 """
1217 ChainNames1Selection, ChainNames2Selection = _ValidateAndSetupChainSelectionsForInterfaceResidues(
1218 MoleculeName1, ChainNames1, MoleculeName2, ChainNames2
1219 )
1220
1221 if ChainNames1Selection is None or ChainNames2Selection is None:
1222 return None
1223
1224 MoleculeSelection1 = "%s and chain %s and (not hydrogens)" % (MoleculeName1, ChainNames1Selection)
1225 MoleculeSelection2 = "%s and chain %s and (not hydrogens)" % (MoleculeName2, ChainNames2Selection)
1226
1227 SelectionCmd1 = "((byresidue (%s) within %.1f of (%s)) and polymer)" % (
1228 MoleculeSelection1,
1229 DistanceCutoff,
1230 MoleculeSelection2,
1231 )
1232 ResiduesInfoMap1 = _GetSelectionChainsAndResiduesInfo(SelectionCmd1)
1233
1234 SelectionCmd2 = "((byresidue (%s) within %.1f of (%s)) and polymer)" % (
1235 MoleculeSelection2,
1236 DistanceCutoff,
1237 MoleculeSelection1,
1238 )
1239 ResiduesInfoMap2 = _GetSelectionChainsAndResiduesInfo(SelectionCmd2)
1240
1241 return ResiduesInfoMap1, ResiduesInfoMap2
1242
1243
1244 def GetInterfaceChainsResiduesBySASAChange(MoleculeName1, ChainNames1, MoleculeName2, ChainNames2, ChangeCutoff=0.75):
1245 """Get information for interface residues between chains in two
1246 molecules based on the change in solvent accessible surface area
1247 (SASA) of a residue in chains in a molecule and chain complex
1248 containing specified chains across both molecules. The chain
1249 specification for molecules may contain multiple chain names
1250 delimited by commas.
1251
1252 Arguments:
1253 MoleculeName1 (str): Name of a PyMOL molecule object.
1254 ChainNames1 (str): A chain name or comma delimited list of chain
1255 names in a molecule.
1256 MoleculeName2 (str): Name of a PyMOL molecule object.
1257 ChainNames2 (str): A chain name or comma delimited list of chain
1258 names in a molecule.
1259 ChangeCutoff (float): SASA change cutoff for heavy atoms in
1260 a interface residue between an individual chain and a complex
1261 containing both chains. Units: Angstroms ** 2
1262
1263 Returns:
1264 dict1: Interface residues in the chain for first molecule. It is a
1265 dictionary containing list of residue names and dictionaries of
1266 residue numbers and residue count for each residue. Names of
1267 residues in the dictionary are not sorted.
1268 dict2: Interface residues in the chain for second molecule.
1269
1270 Examples:
1271
1272 ResiduesInfo1, ResiduesInfo2 =
1273 GetInterfaceResiduesBySASAChange(MolName1,
1274 ChainName1, MolName2, ChainName2, DistanceCutoff)
1275 for ResName in ResiduesInfo1["ResNames"]:
1276 ResCount = ResiduesInfo1["ResCount"][ResName]
1277 ResNums = ResiduesInfo1["ResNum"][ResName]
1278 MiscUtil.PrintInfo("ResName: %s; ResCount: %s; ResNums: %s" %
1279 (ResName, ResCount, ResNums))
1280
1281 """
1282 ChainNames1Selection, ChainNames2Selection = _ValidateAndSetupChainSelectionsForInterfaceResidues(
1283 MoleculeName1, ChainNames1, MoleculeName2, ChainNames2
1284 )
1285
1286 if ChainNames1Selection is None or ChainNames2Selection is None:
1287 return None
1288
1289 # Get ready to calculate solvent accessible surface area..
1290 CurrentDotSolvent = cmd.get("dot_solvent")
1291 cmd.set("dot_solvent", 1)
1292
1293 # Setup tmp object names...
1294 TmpComplexName = "Tmp1_%s_%s" % (MoleculeName1, MoleculeName2)
1295 TmpChainName1 = "Tmp2_%s" % (MoleculeName1)
1296 TmpChainName2 = "Tmp3_%s" % (MoleculeName2)
1297
1298 # Setup complex...
1299 TmpComplexSelection = (
1300 "(%s and chain %s and polymer and not hydrogens) or (%s and chain %s and polymer and not hydrogens)"
1301 % (MoleculeName1, ChainNames1Selection, MoleculeName2, ChainNames2Selection)
1302 )
1303 cmd.create(TmpComplexName, "(%s)" % (TmpComplexSelection))
1304
1305 # Calculate SASA for complex and load it into b...
1306 cmd.get_area(TmpComplexName, load_b=1)
1307 cmd.alter(TmpComplexName, "q=b")
1308
1309 # Setup individual chains and calculate SASA...
1310 TmpChainNameSelection1 = "%s and (chain %s)" % (TmpComplexName, ChainNames1Selection)
1311 cmd.extract(TmpChainName1, "(%s)" % TmpChainNameSelection1)
1312 cmd.get_area(TmpChainName1, load_b=1)
1313
1314 TmpChainNameSelection2 = "%s and (chain %s)" % (TmpComplexName, ChainNames2Selection)
1315 cmd.extract(TmpChainName2, "(%s)" % TmpChainNameSelection2)
1316 cmd.get_area(TmpChainName2, load_b=1)
1317
1318 # Calculate SASA difference for individual chains...
1319 TmpChainNamesSelection = "(%s or %s)" % (TmpChainName1, TmpChainName2)
1320 cmd.alter(TmpChainNamesSelection, "b=b-q")
1321
1322 ResiduesInfoMap1 = _GetChainsResiduesInfoForSASAChange(TmpChainNamesSelection, TmpChainName1, ChangeCutoff)
1323 ResiduesInfoMap2 = _GetChainsResiduesInfoForSASAChange(TmpChainNamesSelection, TmpChainName2, ChangeCutoff)
1324
1325 # Delete tmp objects...
1326 cmd.delete(TmpComplexName)
1327 cmd.delete(TmpChainName1)
1328 cmd.delete(TmpChainName2)
1329
1330 # Restore current dot solvent...
1331 cmd.set("dot_solvent", CurrentDotSolvent)
1332
1333 return ResiduesInfoMap1, ResiduesInfoMap2
1334
1335
1336 def _GetChainsResiduesInfoForSASAChange(SelectionCmd, MoleculeName, ChangeCutoff):
1337 """Get residue info for SASA change."""
1338
1339 # Retrieve data...
1340 stored.ResiduesInfo = []
1341 cmd.iterate(SelectionCmd, "stored.ResiduesInfo.append([model, chain, resi, resn, b])")
1342
1343 # Calculate SASA change for each residue...
1344 SASAChangeMap = {}
1345 SASAChangeMap["ChainIDs"] = []
1346 SASAChangeMap["ResIDs"] = {}
1347 SASAChangeMap["ResSASAChange"] = {}
1348
1349 for Model, ChainID, ResNum, ResName, AtomSASAChange in stored.ResiduesInfo:
1350 if not re.match(Model, MoleculeName, re.I):
1351 continue
1352 ResID = "%s_%s" % (ResName, ResNum)
1353
1354 if ChainID not in SASAChangeMap["ChainIDs"]:
1355 # Track new chain ID and intialize SASA change information...
1356 SASAChangeMap["ChainIDs"].append(ChainID)
1357 SASAChangeMap["ResIDs"][ChainID] = []
1358 SASAChangeMap["ResSASAChange"][ChainID] = {}
1359
1360 if ResID in SASAChangeMap["ResSASAChange"][ChainID]:
1361 SASAChangeMap["ResSASAChange"][ChainID][ResID] += AtomSASAChange
1362 else:
1363 # Track new residue ID...
1364 SASAChangeMap["ResIDs"][ChainID].append(ResID)
1365 SASAChangeMap["ResSASAChange"][ChainID][ResID] = AtomSASAChange
1366
1367 # Identify residues with SASA change greater than the specified cutoff value...
1368 SelectionInfoMap = {}
1369 SelectionInfoMap["ChainIDs"] = []
1370
1371 SelectionInfoMap["ResNames"] = {}
1372 SelectionInfoMap["ResNum"] = {}
1373 SelectionInfoMap["ResCount"] = {}
1374
1375 for ChainID in SASAChangeMap["ChainIDs"]:
1376 for ResID in SASAChangeMap["ResIDs"][ChainID]:
1377 ResSASAChange = SASAChangeMap["ResSASAChange"][ChainID][ResID]
1378 if abs(ResSASAChange) < ChangeCutoff:
1379 continue
1380 ResName, ResNum = ResID.split("_")
1381
1382 if ChainID not in SelectionInfoMap["ChainIDs"]:
1383 # Track new chain ID and intialize residues information...
1384 SelectionInfoMap["ChainIDs"].append(ChainID)
1385 SelectionInfoMap["ResNames"][ChainID] = []
1386 SelectionInfoMap["ResNum"][ChainID] = {}
1387 SelectionInfoMap["ResCount"][ChainID] = {}
1388
1389 if ResName in SelectionInfoMap["ResNames"][ChainID]:
1390 if ResNum not in SelectionInfoMap["ResNum"][ChainID][ResName]:
1391 # Same residue name but different residue number
1392 SelectionInfoMap["ResNum"][ChainID][ResName].append(ResNum)
1393 SelectionInfoMap["ResCount"][ChainID][ResName] += 1
1394 else:
1395 # Track new residue information...
1396 SelectionInfoMap["ResNames"][ChainID].append(ResName)
1397
1398 SelectionInfoMap["ResNum"][ChainID][ResName] = []
1399 SelectionInfoMap["ResNum"][ChainID][ResName].append(ResNum)
1400
1401 SelectionInfoMap["ResCount"][ChainID][ResName] = 1
1402
1403 return SelectionInfoMap
1404
1405
1406 def _ValidateAndSetupChainSelectionsForInterfaceResidues(MoleculeName1, ChainNames1, MoleculeName2, ChainNames2):
1407 """Validate and setup chains name selectons for idenfitying interface residues."""
1408
1409 ChainNames1 = re.sub(" ", "", ChainNames1)
1410 ChainNames2 = re.sub(" ", "", ChainNames2)
1411
1412 if not (len(MoleculeName1) and len(ChainNames1) and len(MoleculeName2) and len(ChainNames2)):
1413 return None, None
1414
1415 # Setup chain names for PyMOL selections...
1416 ChainNames1Selection = "+".join(ChainNames1.split(","))
1417 ChainNames2Selection = "+".join(ChainNames2.split(","))
1418
1419 return ChainNames1Selection, ChainNames2Selection
1420
1421
1422 def _GetSelectionChainsAndResiduesInfo(SelectionCmd):
1423 """Get chain names, residue names and count information for a selection."""
1424
1425 # Retrieve atoms...
1426 stored.SelectionInfo = []
1427 cmd.iterate(SelectionCmd, "stored.SelectionInfo.append([chain, resi, resn])")
1428
1429 # Retrieve chains and residues...
1430 SelectionInfoMap = {}
1431 SelectionInfoMap["ChainIDs"] = []
1432
1433 SelectionInfoMap["ResNames"] = {}
1434 SelectionInfoMap["ResNum"] = {}
1435 SelectionInfoMap["ResCount"] = {}
1436
1437 for ChainID, ResNum, ResName in stored.SelectionInfo:
1438 if ChainID not in SelectionInfoMap["ChainIDs"]:
1439 # Track new chain ID and intialize residues information...
1440 SelectionInfoMap["ChainIDs"].append(ChainID)
1441 SelectionInfoMap["ResNames"][ChainID] = []
1442 SelectionInfoMap["ResNum"][ChainID] = {}
1443 SelectionInfoMap["ResCount"][ChainID] = {}
1444
1445 if ResName in SelectionInfoMap["ResNames"][ChainID]:
1446 if ResNum not in SelectionInfoMap["ResNum"][ChainID][ResName]:
1447 # Same residue name but different residue number
1448 SelectionInfoMap["ResNum"][ChainID][ResName].append(ResNum)
1449 SelectionInfoMap["ResCount"][ChainID][ResName] += 1
1450 else:
1451 # Track new residue information...
1452 SelectionInfoMap["ResNames"][ChainID].append(ResName)
1453
1454 SelectionInfoMap["ResNum"][ChainID][ResName] = []
1455 SelectionInfoMap["ResNum"][ChainID][ResName].append(ResNum)
1456
1457 SelectionInfoMap["ResCount"][ChainID][ResName] = 1
1458
1459 return SelectionInfoMap
1460
1461
1462 def _GetSelectionResiduesInfo(SelectionCmd):
1463 """Get residue names and count information for a selection."""
1464
1465 # Retrieve atoms...
1466 stored.SelectionInfo = []
1467 cmd.iterate(SelectionCmd, "stored.SelectionInfo.append([resi, resn])")
1468
1469 # Retrieve residues...
1470 SelectionInfoMap = {}
1471 SelectionInfoMap["ResNames"] = []
1472 SelectionInfoMap["ResNum"] = {}
1473 SelectionInfoMap["ResCount"] = {}
1474
1475 for ResNum, ResName in stored.SelectionInfo:
1476 if ResName in SelectionInfoMap["ResNames"]:
1477 if ResNum not in SelectionInfoMap["ResNum"][ResName]:
1478 # Same residue name but different residue number
1479 SelectionInfoMap["ResNum"][ResName].append(ResNum)
1480 SelectionInfoMap["ResCount"][ResName] += 1
1481 else:
1482 SelectionInfoMap["ResNames"].append(ResName)
1483
1484 SelectionInfoMap["ResNum"][ResName] = []
1485 SelectionInfoMap["ResNum"][ResName].append(ResNum)
1486
1487 SelectionInfoMap["ResCount"][ResName] = 1
1488
1489 return SelectionInfoMap
1490
1491
1492 def _GetSelectionPhiPsiResiduesInfo(SelectionCmd, Categorize):
1493 """Get phi and psi torsion angle information for residues in a selection
1494 with in a chain.
1495
1496 The phi and psi angles are optionally categorized into the following groups
1497 corresponding to four types of Ramachandran plots:
1498
1499 General: All residues except glycine, proline, or pre-proline
1500 Glycine: Only glycine residues
1501 Proline: Only proline residues
1502 Pre-Proline: Only residues before proline not including glycine or proline
1503
1504 """
1505
1506 # Initialize...
1507 SelectionInfoMap = {}
1508 SelectionInfoMap["ResNums"] = []
1509 SelectionInfoMap["ResName"] = {}
1510 SelectionInfoMap["Phi"] = {}
1511 SelectionInfoMap["Psi"] = {}
1512 SelectionInfoMap["Category"] = {}
1513
1514 # Retrieve phi and psi info...
1515 PhiPsiInfo = _GetSelectionPhiPsiInfo(SelectionCmd, Categorize)
1516 if PhiPsiInfo is None:
1517 return SelectionInfoMap
1518
1519 # Track...
1520 for Model, ChainID, ResNum, ResName, Phi, Psi, Category in PhiPsiInfo:
1521 if ResNum in SelectionInfoMap["ResName"]:
1522 continue
1523
1524 SelectionInfoMap["ResNums"].append(ResNum)
1525 SelectionInfoMap["ResName"][ResNum] = ResName
1526 SelectionInfoMap["Phi"][ResNum] = Phi
1527 SelectionInfoMap["Psi"][ResNum] = Psi
1528 SelectionInfoMap["Category"][ResNum] = Category
1529
1530 return SelectionInfoMap
1531
1532
1533 def _GetSelectionPhiPsiChainsAndResiduesInfo(SelectionCmd, Categorize):
1534 """Get phi and psi torsion angle information for residues in a selection
1535 across chains in a molecule.
1536
1537 The phi and psi angles are optionally categorized into the following groups
1538 corresponding to four types of Ramachandran plots:
1539
1540 General: All residues except glycine, proline, or pre-proline
1541 Glycine: Only glycine residues
1542 Proline: Only proline residues
1543 Pre-Proline: Only residues before proline not including glycine or proline
1544
1545 """
1546
1547 # Initialize...
1548 SelectionInfoMap = {}
1549 SelectionInfoMap["ChainIDs"] = []
1550 SelectionInfoMap["ResNums"] = {}
1551 SelectionInfoMap["ResName"] = {}
1552 SelectionInfoMap["Phi"] = {}
1553 SelectionInfoMap["Psi"] = {}
1554 SelectionInfoMap["Category"] = {}
1555
1556 # Retrieve phi and psi info...
1557 PhiPsiInfo = _GetSelectionPhiPsiInfo(SelectionCmd, Categorize)
1558 if PhiPsiInfo is None:
1559 return SelectionInfoMap
1560
1561 # Track...
1562 for Model, ChainID, ResNum, ResName, Phi, Psi, Category in PhiPsiInfo:
1563 if ChainID not in SelectionInfoMap["ResNums"]:
1564 # Track new chain ID and initialize residues information...
1565 SelectionInfoMap["ChainIDs"].append(ChainID)
1566
1567 SelectionInfoMap["ResNums"][ChainID] = []
1568 SelectionInfoMap["ResName"][ChainID] = {}
1569 SelectionInfoMap["Phi"][ChainID] = {}
1570 SelectionInfoMap["Psi"][ChainID] = {}
1571 SelectionInfoMap["Category"][ChainID] = {}
1572
1573 # Check for duplicates...
1574 if ResNum in SelectionInfoMap["ResName"][ChainID]:
1575 continue
1576
1577 # Track new residues information...
1578 SelectionInfoMap["ResNums"][ChainID].append(ResNum)
1579 SelectionInfoMap["ResName"][ChainID][ResNum] = ResName
1580 SelectionInfoMap["Phi"][ChainID][ResNum] = Phi
1581 SelectionInfoMap["Psi"][ChainID][ResNum] = Psi
1582 SelectionInfoMap["Category"][ChainID][ResNum] = Category
1583
1584 return SelectionInfoMap
1585
1586
1587 def _GetSelectionPhiPsiCategoriesResiduesInfo(SelectionCmd):
1588 """Get phi and psi torsion angle information for residues in a selection
1589 with in a chain.
1590
1591 The phi and psi angles are optionally categorized into the following groups
1592 corresponding to four types of Ramachandran plots:
1593
1594 General: All residues except glycine, proline, or pre-proline
1595 Glycine: Only glycine residues
1596 Proline: Only proline residues
1597 Pre-Proline: Only residues before proline not including glycine or proline
1598
1599 """
1600
1601 # Initialize...
1602 PhiPsiInfoMaps = {}
1603 PhiPsiInfoMaps["Maps"] = []
1604 for Category in ["General", "Glycine", "Proline", "Pre-Proline"]:
1605 PhiPsiInfoMap = {}
1606 PhiPsiInfoMap["ResNums"] = []
1607 PhiPsiInfoMap["ResName"] = {}
1608 PhiPsiInfoMap["Phi"] = {}
1609 PhiPsiInfoMap["Psi"] = {}
1610 PhiPsiInfoMap["Category"] = {}
1611
1612 PhiPsiInfoMaps[Category] = PhiPsiInfoMap
1613 PhiPsiInfoMaps["Maps"].append(PhiPsiInfoMap)
1614
1615 # Retrieve phi and psi info...
1616 PhiPsiInfo = _GetSelectionPhiPsiInfo(SelectionCmd, True)
1617 if PhiPsiInfo is None:
1618 return PhiPsiInfoMaps["Maps"]
1619
1620 Index = -1
1621 for Model, ChainID, ResNum, ResName, Phi, Psi, Category in PhiPsiInfo:
1622 Index += 1
1623
1624 if ResNum in PhiPsiInfoMaps[Category]["ResName"]:
1625 continue
1626
1627 # Track...
1628 PhiPsiInfoMaps[Category]["ResNums"].append(ResNum)
1629 PhiPsiInfoMaps[Category]["ResName"][ResNum] = ResName
1630 PhiPsiInfoMaps[Category]["Phi"][ResNum] = Phi
1631 PhiPsiInfoMaps[Category]["Psi"][ResNum] = Psi
1632 PhiPsiInfoMaps[Category]["Category"][ResNum] = Category
1633
1634 return PhiPsiInfoMaps["Maps"]
1635
1636
1637 def _GetSelectionPhiPsiInfo(SelectionCmd, Categorize=False):
1638 """Get phi and psi angles for a selection along with information regarding
1639 model, chain, residue number, and residue name.
1640
1641 The phi and psi angles are optionally categorized into the following groups
1642 corresponding to four types of Ramachandran plots:
1643
1644 General: All residues except glycine, proline, or pre-proline
1645 Glycine: Only glycine residues
1646 Proline: Only proline residues
1647 Pre-Proline: Only residues before proline not including glycine or proline
1648
1649 """
1650
1651 # Retrieve phi and psi values...
1652 PhiPsiInfoMap = cmd.get_phipsi("(%s)" % SelectionCmd)
1653 if PhiPsiInfoMap is None:
1654 return None
1655
1656 # Sort keys corresponding to model name and residue numbers...
1657 PhiPsiKeys = sorted(PhiPsiInfoMap.keys())
1658
1659 # Retrieve related information...
1660 PhiPsiInfoList = []
1661
1662 Category = None
1663 for Key in PhiPsiKeys:
1664 Model, Index = Key
1665 Phi, Psi = PhiPsiInfoMap[Key]
1666
1667 stored.PhiPsiInfoList = []
1668 cmd.iterate("(%s`%d)" % (Model, Index), "stored.PhiPsiInfoList.append([model, chain, resi, resn])")
1669 for Model, Chain, ResNum, ResName in stored.PhiPsiInfoList:
1670 PhiPsiInfoList.append([Model, Chain, ResNum, ResName, Phi, Psi, Category])
1671
1672 if Categorize:
1673 _CategorizePhiPsiAnglesInfo(PhiPsiInfoList)
1674
1675 return PhiPsiInfoList
1676
1677
1678 def _CategorizePhiPsiAnglesInfo(PhiPsiInfo):
1679 """The phi and psi angles are optionally categorized into the following groups
1680 corresponding to four types of Ramachandran plots:
1681
1682 General: All residues except glycine, proline, or pre-proline
1683 Glycine: Only glycine residues
1684 Proline: Only proline residues
1685 Pre-Proline: Only residues before proline not including glycine or proline
1686
1687 """
1688
1689 Index = -1
1690 LastIndex = len(PhiPsiInfo) - 1
1691 PhiPsiCategories = []
1692 for Model, ChainID, ResNum, ResName, Phi, Psi, CategoryPlaceHolder in PhiPsiInfo:
1693 Index += 1
1694 if re.match("^Gly$", ResName, re.I):
1695 # Gly: Only glycine residues
1696 Category = "Glycine"
1697 elif re.match("^Pro$", ResName, re.I):
1698 # Pro: Only proline residues
1699 Category = "Proline"
1700 elif _IsPreProlinePhiPsiAngle(PhiPsiInfo, Index, LastIndex):
1701 # Pre-Proline: Only residues before proline not including glycine or proline
1702 Category = "Pre-Proline"
1703 else:
1704 # General: All residues except Gly, Pro, or pre-Pro
1705 Category = "General"
1706 # Track categories...
1707 PhiPsiCategories.append(Category)
1708
1709 # Update category in PhiPsiInfo...
1710 CategoryIndex = 6
1711 for Index, Category in enumerate(PhiPsiCategories):
1712 PhiPsiInfo[Index][CategoryIndex] = Category
1713
1714
1715 def _IsPreProlinePhiPsiAngle(PhiPsiInfo, Index, LastIndex):
1716 """Check for Pre-Proline phi and psi angles."""
1717
1718 # Pre-Proline: Only residues before proline not including glycine or proline
1719
1720 # Not a last residue...
1721 NextIndex = Index + 1
1722 if NextIndex >= LastIndex:
1723 return False
1724
1725 # Next residue is proline...
1726 if not re.match("^Pro$", PhiPsiInfo[NextIndex][3], re.I):
1727 return False
1728
1729 # Current residue is not Gly or Pro...
1730 NextResName = PhiPsiInfo[Index][3]
1731 if re.match("^(Gly|Pro)$", NextResName, re.I):
1732 return False
1733
1734 # Next chain ID is same as current chain ID...
1735 CurrentChainID = PhiPsiInfo[Index][1]
1736 NextChainID = PhiPsiInfo[NextIndex][1]
1737 if not re.match("^%s$" % CurrentChainID, NextChainID):
1738 return False
1739
1740 # Current and next residue numbers are sequential...
1741 CurrentResNum = int(PhiPsiInfo[Index][2])
1742 NextResNum = int(PhiPsiInfo[NextIndex][2])
1743 if not (NextResNum - CurrentResNum == 1):
1744 return False
1745
1746 return True
1747
1748
1749 def _GetSelectionResiduesBValuesInfo(SelectionCmd):
1750 """Get B values info for residues in a chain."""
1751
1752 # Retrieve data...
1753 stored.ResiduesInfo = []
1754 cmd.iterate(SelectionCmd, "stored.ResiduesInfo.append([resi, resn, b])")
1755
1756 # Setup B-values for each residue...
1757 BValuesInfoMap = {}
1758 BValuesInfoMap["ResIDs"] = []
1759 BValuesInfoMap["BValue"] = {}
1760
1761 for ResNum, ResName, AtomBValue in stored.ResiduesInfo:
1762 ResID = "%s_%s" % (ResName, ResNum)
1763
1764 if ResID in BValuesInfoMap["BValue"]:
1765 BValuesInfoMap["BValue"][ResID] += AtomBValue
1766 else:
1767 # Track new residue ID...
1768 BValuesInfoMap["ResIDs"].append(ResID)
1769 BValuesInfoMap["BValue"][ResID] = AtomBValue
1770
1771 return BValuesInfoMap
1772
1773
1774 def _GetResiduesInfoFromResiduesBValues(ResiduesBValuesInfoMap, Mode, Cutoff):
1775 """Get residues info map using residues B values."""
1776
1777 GreaterThanEquals, GreaterThan, LessThanEquals, LessThan, Equals = [False] * 5
1778 if re.match("^>=$", Mode, re.I):
1779 GreaterThanEquals = True
1780 elif re.match("^>$", Mode, re.I):
1781 GreaterThan = True
1782 elif re.match("^<=$", Mode, re.I):
1783 LessThanEquals = True
1784 elif re.match("^<$", Mode, re.I):
1785 LessThan = True
1786 elif re.match("^=$", Mode, re.I):
1787 Equals = True
1788 else:
1789 MiscUtil.PrintError(
1790 "PyMOLUtil._GetResiduesInfoFromResiduesBValues: The value, %s, specified for Mode is not valid. Supported values: >=, >, <=, <, ="
1791 )
1792
1793 # Setup residues info map...
1794 ResiduesInfoMap = {}
1795 ResiduesInfoMap["ResNames"] = []
1796 ResiduesInfoMap["ResNum"] = {}
1797 ResiduesInfoMap["ResCount"] = {}
1798
1799 for ResID in ResiduesBValuesInfoMap["ResIDs"]:
1800 ResName, ResNum = ResID.split("_")
1801 ResBValue = ResiduesBValuesInfoMap["BValue"][ResID]
1802
1803 if GreaterThanEquals:
1804 if ResBValue < Cutoff:
1805 continue
1806 elif GreaterThan:
1807 if ResBValue <= Cutoff:
1808 continue
1809 elif LessThanEquals:
1810 if ResBValue > Cutoff:
1811 continue
1812 elif LessThan:
1813 if ResBValue >= Cutoff:
1814 continue
1815 elif Equals:
1816 if ResBValue != Cutoff:
1817 continue
1818
1819 if ResName in ResiduesInfoMap["ResNames"]:
1820 if ResNum not in ResiduesInfoMap["ResNum"][ResName]:
1821 # Same residue name but different residue number
1822 ResiduesInfoMap["ResNum"][ResName].append(ResNum)
1823 ResiduesInfoMap["ResCount"][ResName] += 1
1824 else:
1825 ResiduesInfoMap["ResNames"].append(ResName)
1826
1827 ResiduesInfoMap["ResNum"][ResName] = []
1828 ResiduesInfoMap["ResNum"][ResName].append(ResNum)
1829
1830 ResiduesInfoMap["ResCount"][ResName] = 1
1831
1832 return ResiduesInfoMap
1833
1834
1835 def ProcessChainsAndLigandsOptionsInfo(
1836 ChainsAndLigandsInfo, ChainsOptionName, ChainsOptionValue, LigandsOptionName=None, LigandsOptionValue=None
1837 ):
1838 """Process specified chain and ligand IDs using command line options.
1839
1840 Arguments:
1841 ChainsAndLigandsInfo (dict): A dictionary containing information
1842 existing chains and ligands.
1843 ChainsOptionName (str): Name of command line chains option.
1844 ChainsOptionValue (str): Value for command line chains option.
1845 LigandsOptionName (str): Name of command line ligands option.
1846 LigandsOptionValue (str): Value for command line ligands option.
1847
1848 Returns:
1849 dict: A dictionary containing list of chain identifiers and dictionaries
1850 of chains containing lists of ligand names for each chain.
1851
1852 Examples:
1853
1854 ChainsAndLigandsInfo = ProcessChainsAndLigandsOptionsInfo(
1855 ChainsAndLigandsInfo, "-c, --chainIDs", OptionsInfo["ChainIDs"],
1856 "-l, --ligandIDs", OptionsInfo["LigandIDs"])
1857 for ChainID in ChainsAndLigandsInfo["ChainIDs"]:
1858 for LigandID in ChainsAndLigandsInfo["LigandIDs"][ChainID]:
1859 MiscUtil.PrintInfo("ChainID: %s; LigandID: %s" % (ChainID,
1860 LigandID))
1861
1862 """
1863 SpecifiedChainsAndLigandsInfo = {}
1864 SpecifiedChainsAndLigandsInfo["ChainIDs"] = []
1865 SpecifiedChainsAndLigandsInfo["LigandIDs"] = {}
1866
1867 if ChainsOptionValue is None:
1868 return SpecifiedChainsAndLigandsInfo
1869
1870 _ProcessChainIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo, ChainsOptionName, ChainsOptionValue)
1871
1872 if LigandsOptionValue is None:
1873 return SpecifiedChainsAndLigandsInfo
1874
1875 _ProcessLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo, LigandsOptionName, LigandsOptionValue)
1876
1877 return SpecifiedChainsAndLigandsInfo
1878
1879
1880 def _ProcessChainIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo, ChainsOptionName, ChainsOptionValue):
1881 """Process chain IDs"""
1882
1883 MiscUtil.PrintInfo("Processing chain IDs...")
1884
1885 if re.match("^All$", ChainsOptionValue, re.I):
1886 SpecifiedChainsAndLigandsInfo["ChainIDs"] = ChainsAndLigandsInfo["ChainIDs"]
1887 return
1888 elif re.match("^(First|Auto)$", ChainsOptionValue, re.I):
1889 FirstChainID = ChainsAndLigandsInfo["ChainIDs"][0] if (len(ChainsAndLigandsInfo["ChainIDs"])) else None
1890 if FirstChainID is not None:
1891 SpecifiedChainsAndLigandsInfo["ChainIDs"].append(FirstChainID)
1892 return
1893
1894 ChainIDs = re.sub(" ", "", ChainsOptionValue)
1895 if not ChainIDs:
1896 MiscUtil.PrintError('No valid value specified using "%s" option.' % ChainsOptionName)
1897
1898 ChainIDsList = ChainsAndLigandsInfo["ChainIDs"]
1899 SpecifiedChainIDsList = []
1900
1901 ChainIDsWords = ChainIDs.split(",")
1902 for ChainID in ChainIDsWords:
1903 if ChainID not in ChainIDsList:
1904 MiscUtil.PrintWarning(
1905 'The chain ID, %s, specified using "%s" option is not valid. It\'ll be ignored. Valid chain IDs: %s'
1906 % (ChainID, ChainsOptionName, ", ".join(ChainIDsList))
1907 )
1908 continue
1909 if ChainID in SpecifiedChainIDsList:
1910 MiscUtil.PrintWarning(
1911 'The chain ID, %s, has already been specified using "%s" option. It\'ll be ignored.'
1912 % (ChainID, ChainsOptionName)
1913 )
1914 continue
1915 SpecifiedChainIDsList.append(ChainID)
1916
1917 if not len(SpecifiedChainIDsList):
1918 MiscUtil.PrintError(
1919 'No valid chain IDs "%s" specified using "%s" option.' % (ChainsOptionValue, ChainsOptionName)
1920 )
1921
1922 SpecifiedChainsAndLigandsInfo["ChainIDs"] = SpecifiedChainIDsList
1923
1924
1925 def _ProcessLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo, LigandsOptionName, LigandsOptionValue):
1926 """Process ligand IDs"""
1927
1928 MiscUtil.PrintInfo("Processing ligand IDs...")
1929
1930 # Intialize ligand IDs...
1931 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1932 SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID] = []
1933
1934 if re.match("^All$", LigandsOptionValue, re.I):
1935 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1936 SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID] = ChainsAndLigandsInfo["LigandIDs"][ChainID]
1937 return
1938 elif re.match("^(Largest|Auto)$", LigandsOptionValue, re.I):
1939 # Setup largest ligand ID for each chain...
1940 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1941 LargestLigandID = (
1942 ChainsAndLigandsInfo["LigandIDs"][ChainID][0]
1943 if (len(ChainsAndLigandsInfo["LigandIDs"][ChainID]))
1944 else None
1945 )
1946 if LargestLigandID is not None:
1947 SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID].append(LargestLigandID)
1948 return
1949
1950 LigandIDs = re.sub(" ", "", LigandsOptionValue)
1951 if not LigandIDs:
1952 MiscUtil.PrintError('No valid value specified using "%s" option.' % LigandsOptionName)
1953
1954 LigandIDsWords = LigandIDs.split(",")
1955
1956 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1957 LigandIDsList = ChainsAndLigandsInfo["LigandIDs"][ChainID]
1958 SpecifiedLigandIDsList = []
1959
1960 for LigandID in LigandIDsWords:
1961 if LigandID not in LigandIDsList:
1962 LigandIDsListNames = ",".join(LigandIDsList) if len(LigandIDsList) else "None"
1963 MiscUtil.PrintWarning(
1964 'The ligand ID, %s, specified using "%s" option is not valid for chain, %s. It\'ll be ignored. Valid ligand IDs: %s'
1965 % (LigandID, LigandsOptionName, ChainID, LigandIDsListNames)
1966 )
1967 continue
1968 if LigandID in SpecifiedLigandIDsList:
1969 MiscUtil.PrintWarning(
1970 'The ligand ID, %s, has already been specified using "%s" option. It\'ll be ignored.'
1971 % (LigandID, LigandsOptionName)
1972 )
1973 continue
1974 SpecifiedLigandIDsList.append(LigandID)
1975
1976 if not len(SpecifiedLigandIDsList):
1977 MiscUtil.PrintWarning(
1978 'No valid ligand IDs "%s" specified using "%s" option for chain ID, %s.'
1979 % (LigandsOptionValue, LigandsOptionName, ChainID)
1980 )
1981
1982 SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID] = SpecifiedLigandIDsList
1983
1984
1985 def ProcessResidueTypesOptionsInfo(ResidueTypesOptionName, ResidueTypesOptionValue):
1986 """Process specified residue types using command line option.
1987
1988 Arguments:
1989 ResidueTypesOptionName (str): Name of command line option.
1990 ResidueTypesOptionValue (str): Value for command line option.
1991
1992 Returns:
1993 list: A list containing names of valid residue types.
1994 dict: A dictionary containing residue types pointing to dictionaries of
1995 color names and list of residues for a residue type.
1996
1997 Examples:
1998
1999 ResidueTypesNamesInfo, ResidueTypesParamsInfo =
2000 ProcessChainsAndLigandsOptionsInfo("-r, --residueTypes",
2001 OptionsInfo["ResidueTypes"])
2002 for ResidueTypeName in ResidueTypesNamesInfo:
2003 MiscUtil.PrintInfo("ResidueType: %s; Color: %s; Residues: %s" %
2004 (ResidueTypeName, ResidueTypeName[ResidueTypeName]["Color"],
2005 " ".join(ResidueTypeName[ResidueTypeName]["Residues"]))
2006
2007 """
2008
2009 # Set up default values for residue types, colors, and names.
2010 ResidueTypesNamesInfo = ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged"]
2011
2012 ResidueTypesParamsInfo = {}
2013 ResidueTypesParamsInfo["Aromatic"] = {"Color": "brightorange", "Residues": ["HIS", "PHE", "TRP", "TYR"]}
2014 ResidueTypesParamsInfo["Hydrophobic"] = {
2015 "Color": "orange",
2016 "Residues": ["ALA", "GLY", "VAL", "LEU", "ILE", "PRO", "MET"],
2017 }
2018 ResidueTypesParamsInfo["Polar"] = {"Color": "palegreen", "Residues": ["ASN", "GLN", "SER", "THR", "CYS"]}
2019 ResidueTypesParamsInfo["Positively_Charged"] = {"Color": "marine", "Residues": ["ARG", "LYS"]}
2020 ResidueTypesParamsInfo["Negatively_Charged"] = {"Color": "red", "Residues": ["ASP", "GLU"]}
2021
2022 ResidueTypes = ResidueTypesOptionValue
2023 if re.match("^auto$", ResidueTypesOptionValue, re.I):
2024 _SetupOtherResidueTypes(ResidueTypesParamsInfo)
2025 return ResidueTypesNamesInfo, ResidueTypesParamsInfo
2026
2027 # Parse specified residue types...
2028 ResidueTypesWords = ResidueTypes.split(",")
2029 if len(ResidueTypesWords) % 3:
2030 MiscUtil.PrintError(
2031 'The number of comma delimited residue type, color, and name triplets, %d, specified using "%s" option must be a multple of 3.'
2032 % (len(ResidueTypesWords), ResidueTypesOptionName)
2033 )
2034
2035 # Set up canonical residue type names...
2036 ValidResidueTypeNames = []
2037 CanonicalResidueTypeNamesMap = {}
2038 for Name in sorted(ResidueTypesNamesInfo):
2039 ValidResidueTypeNames.append(Name)
2040 CanonicalResidueTypeNamesMap[Name.lower()] = Name
2041
2042 # Validate and set residue types, colors, and names..
2043 for Index in range(0, len(ResidueTypesWords), 3):
2044 TypeName = ResidueTypesWords[Index].strip()
2045 ResidueTypeColor = ResidueTypesWords[Index + 1].strip()
2046 ResidueNames = ResidueTypesWords[Index + 2].strip()
2047
2048 ResidueNames = re.sub("[ ]+", " ", ResidueNames)
2049 ResidueNamesWords = ResidueNames.split(" ")
2050
2051 CanonicalTypeName = TypeName.lower()
2052 if CanonicalTypeName not in CanonicalResidueTypeNamesMap:
2053 MiscUtil.PrintError(
2054 'The residue type, %s, specified using "%s" option is not a valid type. Supported residue types: %s'
2055 % (TypeName, ResidueTypesOptionName, ", ".join(ValidResidueTypeNames))
2056 )
2057 ResidueTypeName = CanonicalResidueTypeNamesMap[CanonicalTypeName]
2058
2059 if not ResidueTypeColor:
2060 MiscUtil.PrintError(
2061 'No color name specified for residue type, %s, using "%s" option, %s'
2062 % (TypeName, ResidueTypesOptionName, ResidueTypes)
2063 )
2064
2065 if not ResidueNames:
2066 MiscUtil.PrintError(
2067 'No residue names specified for residue type, %s, using "%s" option, %s'
2068 % (TypeName, ResidueTypesOptionName, ResidueTypes)
2069 )
2070
2071 ResidueTypesParamsInfo[ResidueTypeName]["Color"] = ResidueTypeColor
2072 ResidueTypesParamsInfo[ResidueTypeName]["Residues"] = ResidueNamesWords
2073
2074 _SetupOtherResidueTypes()
2075 return ResidueTypesNamesInfo, ResidueTypesParamsInfo
2076
2077
2078 def _SetupOtherResidueTypes(ResidueTypesParamsInfo):
2079 """Setup other residue types."""
2080
2081 # Set other residues to all specified residues. The other residues are selected by
2082 # performing a negation operation on this list during the creation of PyMOL objects.
2083
2084 ResidueNames = []
2085 for ResiduesType in ResidueTypesParamsInfo:
2086 ResidueNames.extend(ResidueTypesParamsInfo[ResiduesType]["Residues"])
2087
2088 ResidueTypesParamsInfo["Other"] = {}
2089 ResidueTypesParamsInfo["Other"]["Color"] = None
2090 ResidueTypesParamsInfo["Other"]["Residues"] = ResidueNames
2091
2092
2093 def ProcessSurfaceAtomTypesColorsOptionsInfo(ColorOptionName, ColorOptionValue):
2094 """Process specified surafce atom types colors using command line option.
2095
2096 Arguments:
2097 ColorOptionName (str): Name of command line option.
2098 ColorOptionValue (str): Value for command line option.
2099
2100 Returns:
2101 dict: A dictionary containing atom types and colors.
2102
2103 Examples:
2104
2105 AtomTypesColorNamesInfo =
2106 PyMOLUtil.ProcessSurfaceAtomTypesColorsOptionsInfo(
2107 "--surfaceAtomTypesColors", OptionsInfo["SurfaceAtomTypesColors"])
2108
2109 """
2110
2111 # Set up default values for atom type colors...
2112 AtomTypesColorNamesInfo = {
2113 "HydrophobicAtomsColor": "yellow",
2114 "NegativelyChargedAtomsColor": "red",
2115 "PositivelyChargedAtomsColor": "blue",
2116 "OtherAtomsColor": "gray90",
2117 }
2118
2119 AtomTypesColors = ColorOptionValue
2120 if re.match("^auto$", AtomTypesColors, re.I):
2121 return AtomTypesColorNamesInfo
2122
2123 # Parse atom type colors and values...
2124 AtomTypesColorsWords = AtomTypesColors.split(",")
2125 if len(AtomTypesColorsWords) % 2:
2126 MiscUtil.PrintError(
2127 'The number of comma delimited surface atom color types and values, %d, specified using "%s" option must be a multple of 2.'
2128 % (len(AtomTypesColorsWords), ColorOptionName)
2129 )
2130
2131 # Set up canonical atom type colors...
2132 ValidAtomTypesColors = []
2133 CanonicalAtomTypesColorsMap = {}
2134 for Type in sorted(AtomTypesColorNamesInfo):
2135 ValidAtomTypesColors.append(Type)
2136 CanonicalAtomTypesColorsMap[Type.lower()] = Type
2137
2138 # Validate and process specified values...
2139 for Index in range(0, len(AtomTypesColorsWords), 2):
2140 Type = AtomTypesColorsWords[Index].strip()
2141 Color = AtomTypesColorsWords[Index + 1].strip()
2142
2143 Color = re.sub("[ ]+", " ", Color)
2144 ColorWords = Color.split(" ")
2145
2146 CanonicalType = Type.lower()
2147 if CanonicalType not in CanonicalAtomTypesColorsMap:
2148 MiscUtil.PrintError(
2149 'The surface atom color type, %s, specified using "%s" option is not a valid type: Supported atom color types: %s'
2150 % (Type, ColorOptionName, ", ".join(ValidAtomTypesColors))
2151 )
2152 Type = CanonicalAtomTypesColorsMap[CanonicalType]
2153
2154 if not Color:
2155 MiscUtil.PrintError(
2156 'No color type specified for atom color type, %s, using "%s" option.' % (Type, ColorOptionName)
2157 )
2158
2159 ColorWordsLen = len(ColorWords)
2160 if not (ColorWordsLen == 1 or ColorWordsLen == 3):
2161 MiscUtil.PrintError(
2162 'The number, %s, of color name or space delimited RGB values, %s, specified for atom color type, %s, using "%s" option must be 1 or 3.'
2163 % (ColorWordsLen, Color, ColorOptionName, Type)
2164 )
2165
2166 AtomTypesColorNamesInfo[Type] = " ".join(ColorWords)
2167
2168 return AtomTypesColorNamesInfo
2169
2170
2171 def ProcessSaltBridgesChainResiduesOptionsInfo(SaltBridgesOptionName, SaltBridgesOptionValue):
2172 """Process specified salt bridges chain residues using command line option.
2173
2174 Arguments:
2175 SaltBridgesOptionName (str): Name of command line option.
2176 SaltBridgesOptionValue (str): Value for command line option.
2177
2178 Returns:
2179 dict: A dictionary containing salt bridges residue types and residue
2180 names.
2181
2182 Examples:
2183
2184 SaltBridgesChainResiduesInfo =
2185 PyMOLUtil.ProcessSaltBridgesChainResiduesOptionsInfo(
2186 "--saltBridgesChainResidues", OptionsInfo["SaltBridgesChainResidues"])
2187
2188 """
2189
2190 # Set up default values for salt bridges chain residues...
2191 SaltBridgesChainResiduesInfo = {
2192 "Positively_Charged": ["ARG", "LYS", "HIS", "HSP"],
2193 "Negatively_Charged": ["ASP", "GLU"],
2194 }
2195
2196 SaltBridgesChainResidues = SaltBridgesOptionValue
2197 if re.match("^auto$", SaltBridgesChainResidues, re.I):
2198 return SaltBridgesChainResiduesInfo
2199
2200 # Parse salt bridges chain residues types and residue names...
2201 SaltBridgesChainResiduesWords = SaltBridgesChainResidues.split(",")
2202 if len(SaltBridgesChainResiduesWords) % 2:
2203 MiscUtil.PrintError(
2204 'The number of comma delimited salt bridges residue types and names, %d, specified using "%s" option must be a multple of 2.'
2205 % (len(SaltBridgesChainResiduesWords), SaltBridgesOptionName)
2206 )
2207
2208 # Set up canonical salt bridges chain residue types...
2209 ValidSaltBridgesChainResidueTypes = []
2210 CanonicalSaltBridgesChainResiduesMap = {}
2211 for Type in sorted(SaltBridgesChainResiduesInfo):
2212 ValidSaltBridgesChainResidueTypes.append(Type)
2213 CanonicalSaltBridgesChainResiduesMap[Type.lower()] = Type
2214
2215 # Validate and process specified values...
2216 for Index in range(0, len(SaltBridgesChainResiduesWords), 2):
2217 Type = SaltBridgesChainResiduesWords[Index].strip()
2218 Residue = SaltBridgesChainResiduesWords[Index + 1].strip()
2219
2220 Residue = re.sub("[ ]+", " ", Residue)
2221 ResidueWords = Residue.split(" ")
2222
2223 CanonicalType = Type.lower()
2224 if CanonicalType not in CanonicalSaltBridgesChainResiduesMap:
2225 MiscUtil.PrintError(
2226 'The salt bridges chain residue type, %s, specified using "%s" option is not a valid type: Supported salt bridges chain residue types: %s'
2227 % (Type, SaltBridgesOptionName, ", ".join(ValidSaltBridgesChainResidueTypes))
2228 )
2229 Type = CanonicalSaltBridgesChainResiduesMap[CanonicalType]
2230
2231 if not Residue or len(ResidueWords) == 0:
2232 MiscUtil.PrintError(
2233 'No residue specified for salt bridges chain residue type, %s, using "%s" option.'
2234 % (Type, SaltBridgesOptionName)
2235 )
2236
2237 SaltBridgesChainResiduesInfo[Type] = ResidueWords
2238
2239 return SaltBridgesChainResiduesInfo
2240
2241
2242 def ProcessChainSelectionsOptionsInfo(SelectionOptionName, SelectionOptionValue):
2243 """Process names and selections specified using command line option. It
2244 is a pairwise list comma delimited values corresponding to PyMOL object
2245 names and selection specification
2246
2247 Arguments:
2248 SelectionOptionName (str): Name of command line option.
2249 SelectionOptionValue (str): Value for command line option.
2250
2251 Returns:
2252 dict: A dictionary containing lists f names and selection commands.
2253
2254 Examples:
2255
2256 ChainSelectionsInfo =
2257 PyMOLUtil.ProcessChainSelectionsOptionsInfo("--selectionsChain",
2258 OptionsInfo["SelectionChains"])
2259
2260 """
2261
2262 # Initialize...
2263 ChainSelectionsInfo = {}
2264 ChainSelectionsInfo["Names"] = []
2265 ChainSelectionsInfo["Selections"] = []
2266
2267 if re.match("^None$", SelectionOptionValue, re.I):
2268 return ChainSelectionsInfo
2269
2270 # Parse selection chains names and selections...
2271 ChainSelectionsWords = SelectionOptionValue.split(",")
2272 if len(ChainSelectionsWords) % 2:
2273 MiscUtil.PrintError(
2274 'The number of comma delimited selection chains names and selections, %d, specified using "%s" option must be a multple of 2.'
2275 % (len(ChainSelectionsWords), SelectionOptionName)
2276 )
2277
2278 CanonicalNamesMap = {}
2279 for Index in range(0, len(ChainSelectionsWords), 2):
2280 Name = ChainSelectionsWords[Index].strip()
2281 Selection = ChainSelectionsWords[Index + 1].strip()
2282
2283 if not len(Name):
2284 MiscUtil.PrintError(
2285 'A name specified, "%s", using "%s" option is empty.' % (SelectionOptionValue, SelectionOptionName)
2286 )
2287 if not len(Selection):
2288 MiscUtil.PrintError(
2289 'A selection specified, "%s", using "%s" option is empty.' % (SelectionOptionValue, SelectionOptionName)
2290 )
2291
2292 CanonicalName = Name.lower()
2293 if CanonicalName in CanonicalNamesMap:
2294 MiscUtil.PrintError(
2295 'The name %s specified using "%s" option is a duplicate name.' % (Name, SelectionOptionName)
2296 )
2297 CanonicalNamesMap[CanonicalName] = Name
2298
2299 if re.search(r"[^a-zA-Z0-9 _\-]", Name, re.I):
2300 MiscUtil.PrintError(
2301 'The name %s specified using "%s" option contains invalid charactors. Supportted characters: alphanumeric, space, hyphen and underscore..'
2302 )
2303
2304 ChainSelectionsInfo["Names"].append(Name)
2305 ChainSelectionsInfo["Selections"].append(Selection)
2306
2307 return ChainSelectionsInfo
2308
2309
2310 def CalculateCenterOfMass(Selection="all", Quiet=0):
2311 """Calculate center of mass for a selection.
2312
2313 Arguments:
2314 Selection (str): A PyMOL selection.
2315 Quiet (int): Print information.
2316
2317 Returns:
2318 list: X, Y, Z coordinates for center of mass.
2319
2320 """
2321 MassTotal = 0.0
2322 X, Y, Z = [0.0, 0.0, 0.0]
2323
2324 Atoms = cmd.get_model(Selection)
2325 for Atom in Atoms.atom:
2326 Mass = Atom.get_mass()
2327 MassTotal += Mass
2328
2329 X += Atom.coord[0] * Mass
2330 Y += Atom.coord[1] * Mass
2331 Z += Atom.coord[2] * Mass
2332
2333 XCOM = X / MassTotal
2334 YCOM = Y / MassTotal
2335 ZCOM = Z / MassTotal
2336
2337 if not Quiet:
2338 MiscUtil.PrintInfo("PyMOLUtil.CalculateCenterOfMass: %f, %f, %f" % (XCOM, YCOM, ZCOM))
2339
2340 return [XCOM, YCOM, ZCOM]
2341
2342
2343 def ConvertFileFormat(Infile, Outfile, Reinitialize=True, OutputFeedback=True):
2344 """Convert infile to outfile by automatically detecting their formats
2345 from the file extensions.
2346
2347 The formats of both input and output files must be a valid format supported
2348 by PyMOL.
2349
2350 Arguments:
2351 Infile (str): Name of input file.
2352 Outfile (str): Name of outfile file.
2353 Reinitialize (bool): Reinitialize PyMOL before loading input file.
2354 OutputFeedback (bool): Control output feedback.
2355
2356 """
2357
2358 if not os.path.exists(Infile):
2359 MiscUtil.PrintWarning("The input file, %s, doesn't exists.%s..." % (Infile))
2360
2361 if Reinitialize:
2362 cmd.reinitialize()
2363
2364 if not OutputFeedback:
2365 # Turn off output feedback...
2366 MiscUtil.PrintInfo("Disabling output feedback for PyMOL...")
2367 cmd.feedback("disable", "all", "output")
2368
2369 FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
2370 MolName = FileName
2371
2372 cmd.load(Infile, MolName)
2373 cmd.save(Outfile, MolName)
2374 cmd.delete(MolName)
2375
2376 if not OutputFeedback:
2377 # Turn it back on...
2378 MiscUtil.PrintInfo("\nEnabling output feedback for PyMOL...")
2379 cmd.feedback("enable", "all", "output")
2380
2381
2382 def ConvertPMLFileToPSEFile(PMLFile, PSEFile, Reinitialize=True, OutputFeedback=True):
2383 """Convert PML file to PME file.
2384
2385 Arguments:
2386 PMLFile (str): Name of PML file.
2387 PSEFile (str): Name of PSE file.
2388 Reinitialize (bool): Reinitialize PyMOL before loading PML file.
2389 OutputFeedback (bool): Control output feedback.
2390
2391 """
2392
2393 if not os.path.exists(PMLFile):
2394 MiscUtil.PrintWarning("The PML file, %s, doesn't exists.%s..." % (PMLFile))
2395
2396 if Reinitialize:
2397 cmd.reinitialize()
2398
2399 if not OutputFeedback:
2400 # Turn off output feedback...
2401 MiscUtil.PrintInfo("Disabling output feedback for PyMOL...")
2402 cmd.feedback("disable", "all", "output")
2403
2404 cmd.do("@%s" % PMLFile)
2405 cmd.save(PSEFile)
2406
2407 if not OutputFeedback:
2408 # Turn it back on...
2409 MiscUtil.PrintInfo("\nEnabling output feedback for PyMOL...")
2410 cmd.feedback("enable", "all", "output")
2411
2412
2413 def SetupPMLHeaderInfo(ScriptName=None, IncludeLocalPython=True):
2414 """Setup header information for generating PML files. The local Python
2415 functions are optionally embedded in the header information for their
2416 use in PML files.
2417
2418 Arguments:
2419 ScriptName (str): Name of script calling the function.
2420 IncludeLocalPython (bool): Include local Python functions.
2421
2422 Returns:
2423 str: Text containing header information for generating PML files.
2424
2425 """
2426 if ScriptName is None:
2427 HeaderInfo = """\
2428 #
2429 # This file is automatically generated by a script available in MayaChemTools.
2430 #
2431 cmd.reinitialize()"""
2432 else:
2433 HeaderInfo = """\
2434 #
2435 # This file is automatically generated by the following PyMOL script available in
2436 # MayaChemTools: %s
2437 #
2438 cmd.reinitialize() """ % (ScriptName)
2439
2440 if IncludeLocalPython:
2441 PMLForLocalPython = _SetupPMLForLocalPython()
2442 HeaderInfo = "%s\n\n%s" % (HeaderInfo, PMLForLocalPython)
2443
2444 return HeaderInfo
2445
2446
2447 def _SetupPMLForLocalPython():
2448 """Setup local Python functions for PML file."""
2449
2450 PMLForPython = """\
2451 ""
2452 "Setting up local Python functions for PML script..."
2453 ""
2454 python
2455
2456 from __future__ import print_function
2457 import re
2458
2459 def ColorByHydrophobicity(Selection, ColorPalette = "RedToWhite"):
2460 \"""Color by hydrophobicity using hydrophobic values for amino acid
2461 residues corresponding to the Eisenberg hydrophobicity scale.
2462
2463 Possible values for ColorPalette: RedToWhite or WhiteToGreen from most
2464 hydrophobic amino acid to least hydrophobic.
2465
2466 The colors values for amino acids are taken from color_h script avaiable
2467 as part of the Script Library at PyMOL Wiki.
2468
2469 \"""
2470
2471 if not re.match("^(RedToWhite|WhiteToGreen)$", ColorPalette, re.I):
2472 print("Invalid ColorPalette value: %s. Valid values: RedToWhite, WhiteToGreen" % ColorPalette)
2473
2474 ResColors = {}
2475 ColorType = ""
2476
2477 if re.match("^WhiteToGreen$", ColorPalette, re.I):
2478 ColorType = "H2"
2479 ResColors = {"ile" : [0.938,1,0.938], "phe" : [0.891,1,0.891], "val" : [0.844,1,0.844], "leu" : [0.793,1,0.793], "trp" : [0.746,1,0.746], "met" : [0.699,1,0.699], "ala" : [0.652,1,0.652], "gly" : [0.606,1,0.606], "cys" : [0.555,1,0.555], "tyr" : [0.508,1,0.508], "pro" : [0.461,1,0.461], "thr" : [0.414,1,0.414], "ser" : [0.363,1,0.363], "his" : [0.316,1,0.316], "glu" : [0.27,1,0.27], "asn" : [0.223,1,0.223], "gln" : [0.176,1,0.176], "asp" : [0.125,1,0.125], "lys" : [0.078,1,0.078], "arg" : [0.031,1,0.031]}
2480 else:
2481 ColorType = "H1"
2482 ResColors = {"ile" : [0.996,0.062,0.062], "phe" : [0.996,0.109,0.109], "val" : [0.992,0.156,0.156], "leu" : [0.992,0.207,0.207], "trp" : [0.992,0.254,0.254], "met" : [0.988,0.301,0.301], "ala" : [0.988,0.348,0.348], "gly" : [0.984,0.394,0.394], "cys" : [0.984,0.445,0.445], "tyr" : [0.984,0.492,0.492], "pro" : [0.980,0.539,0.539], "thr" : [0.980,0.586,0.586], "ser" : [0.980,0.637,0.637], "his" : [0.977,0.684,0.684], "glu" : [0.977,0.730,0.730], "asn" : [0.973,0.777,0.777], "gln" : [0.973,0.824,0.824], "asp" : [0.973,0.875,0.875], "lys" : [0.899,0.922,0.922], "arg" : [0.899,0.969,0.969]}
2483
2484 # Set up colors...
2485 for ResName in ResColors:
2486 ColorName = "color_%s_%s" % (ResName, ColorType)
2487 cmd.set_color(ColorName, ResColors[ResName])
2488
2489 ResSelection = "(%s and resn %s*)" % (Selection, ResName)
2490 cmd.color(ColorName, ResSelection)
2491
2492 cmd.extend("ColorByHydrophobicity", ColorByHydrophobicity)
2493
2494 def ColorAtomsByHydrophobicityAndCharge(Selection, HydrophobicAtomsColor = "yellow", NegativelyChargedAtomsColor = "red", PositivelyChargedAtomsColor = "blue", OtherAtomsColor = "gray90"):
2495 \"""Color atoms in amino acids by their propensity to make hydrophobic and
2496 charge interactions [REF 140]. The atom names in standard amino acid
2497 residues are used to identify atom types as shown below:
2498
2499 Hydrophobic: C atoms not bound to N or O atoms
2500 NegativelyCharged: Side chain O atoms in ASP and GLU
2501 PositivelyCharged: Side chain N atoms in ARG and LYS
2502 Others: Remaining atoms in polar and other residues
2503
2504 The following color scheme is used by default:
2505
2506 Hydrophobic: yellow
2507 NegativelyCharged: red
2508 PositivelyCharged: blue
2509 Others: gray90
2510
2511 The amino acid atom names to color specific atoms are taken from YRB.py
2512 script [ REF 140]. The color values may also be specified as comma delimited
2513 RGB triplets. For example: HydrophobicAtomsColor = "0.950 0.78 0.0",
2514 NegativelyChargedAtomsColor = "1.0 0.4 0.4", PositivelyChargedAtomsColor
2515 = "0.2 0.5 0.8", OtherAtomsColor = "0.95 0.95 0.95"
2516
2517 \"""
2518
2519 # Process colors...
2520 Colors = {"HydrophobicAtomsColor": HydrophobicAtomsColor, "NegativelyChargedAtomsColor": NegativelyChargedAtomsColor, "PositivelyChargedAtomsColor": PositivelyChargedAtomsColor, "OtherAtomsColor": OtherAtomsColor}
2521 ColorsRGB = {}
2522 for ColorKey, ColorValue in Colors.items():
2523 if re.search(" ", ColorValue):
2524 ColorRGB = ColorValue.split(" ")
2525 else:
2526 ColorRGB = cmd.get_color_tuple(cmd.get_color_index(ColorValue))
2527 ColorsRGB[ColorKey] = ColorRGB
2528
2529 # Set up colors...
2530 for ColorKey, ColorValue in ColorsRGB.items():
2531 cmd.set_color(ColorKey, ColorValue)
2532
2533 # Set up colors for atom names across all resiudes...
2534 AtomColors = {"OtherAtomsColor": "N,C,CA,O", "HydrophobicAtomsColor": "CB"}
2535
2536 # Set up colors for atom names across specific resiudes...
2537 ResAtomColors = {"arg" : {"HydrophobicAtomsColor": "CG", "PositivelyChargedAtomsColor": "NE,NH2,NH1", "OtherAtomsColor": "CD,CZ"}, "asn" : {"OtherAtomsColor": "CG,OD1,ND2"}, "asp" : {"NegativelyChargedAtomsColor": "OD2,OD1", "OtherAtomsColor": "CG"}, "cys" : {"OtherAtomsColor": "SG"}, "gln" : {"HydrophobicAtomsColor": "CG", "OtherAtomsColor": "CD,OE1,NE2"}, "glu" : {"HydrophobicAtomsColor": "CG", "NegativelyChargedAtomsColor": "OE1,OE2", "OtherAtomsColor": "CD"}, "his" : {"OtherAtomsColor": "CG,CD2,ND1,NE2,CE1"}, "ile" : {"HydrophobicAtomsColor": "CG1,CG2,CD1"}, "leu" : {"HydrophobicAtomsColor": "CG,CD1,CD2"}, "lys" : {"HydrophobicAtomsColor": "CG,CD", "PositivelyChargedAtomsColor": "NZ", "OtherAtomsColor": "CE"}, "met" : {"HydrophobicAtomsColor": "CG,CE", "OtherAtomsColor": "SD"}, "phe" : {"HydrophobicAtomsColor": "CG,CD1,CE1,CZ,CE2,CD2"}, "pro" : {"HydrophobicAtomsColor": "CG", "OtherAtomsColor": "CD"}, "ser" : {"OtherAtomsColor": "CB,OG"}, "thr" : {"HydrophobicAtomsColor": "CG2", "OtherAtomsColor": "CB,OG1"}, "trp" : {"HydrophobicAtomsColor": "CG,CD2,CZ2,CH2,CZ3,CE3", "OtherAtomsColor": "CD1,NE1,CE2"}, "tyr" : {"HydrophobicAtomsColor": "CG,CE1,CD1,CE2,CD2", "OtherAtomsColor": "CZ,OH"}, "val" : {"HydrophobicAtomsColor": "CG1,CG2"}}
2538
2539 # Color atom names across all resiudes...
2540 for ColorName in AtomColors:
2541 AtomNames = AtomColors[ColorName]
2542 AtomsSelection = "(%s and name %s)" % (Selection, AtomNames)
2543 cmd.color(ColorName, AtomsSelection)
2544
2545 # Color hydrogen atoms across all residues to other color...
2546 AtomsSelection = "(%s and hydro)" % (Selection)
2547 cmd.color("OtherAtomsColor", AtomsSelection)
2548
2549 # Color atom names across specific resiudes...
2550 for ResName in ResAtomColors:
2551 for ColorName in ResAtomColors[ResName]:
2552 AtomNames = ResAtomColors[ResName][ColorName]
2553 AtomsSelection = "(%s and resn %s and name %s)" % (Selection, ResName, AtomNames)
2554 cmd.color(ColorName, AtomsSelection)
2555
2556 cmd.extend("ColorAtomsByHydrophobicityAndCharge", ColorAtomsByHydrophobicityAndCharge)
2557
2558 def CheckAndDeleteEmptyObjects(ObjectNames, ParentObjectName = None):
2559 \"""Delete an empty objects along with optionally deleting their parent.
2560
2561 \"""
2562
2563 ObjectNamesList = ObjectNames.split(",")
2564
2565 AllObjectsEmpty = True
2566 for ObjectName in ObjectNamesList:
2567 ObjectName = ObjectName.strip()
2568 if cmd.count_atoms("(%s)" % ObjectName):
2569 AllObjectsEmpty = False
2570 else:
2571 cmd.delete("%s" % ObjectName)
2572
2573 if AllObjectsEmpty and ParentObjectName is not None:
2574 cmd.delete("%s" % ParentObjectName)
2575
2576 cmd.extend("CheckAndDeleteEmptyObjects", CheckAndDeleteEmptyObjects)
2577
2578 python end"""
2579
2580 return PMLForPython
2581
2582
2583 def SetupPMLForEnableDisable(Name, Enable=True):
2584 """Setup PML command for enabling or disabling display of a PyMOL object.
2585
2586 Arguments:
2587 Name (str): Name of a PyMOL object.
2588 Enable (bool): Display status.
2589
2590 Returns:
2591 str: PML command for enabling or disabling display of an object.
2592
2593 """
2594
2595 if Enable:
2596 PML = """cmd.enable("%s")""" % Name
2597 else:
2598 PML = """cmd.disable("%s")""" % Name
2599
2600 return PML
2601
2602
2603 def SetupPMLForGroup(GroupName, GroupMembersList, Enable=None, Action=None):
2604 """Setup PML commands for creating a group from a list of group members. The
2605 display and open status of the group may be optionally set. The 'None' values
2606 for Enable and Action imply usage of PyMOL defaults for the creation of group.
2607
2608 Arguments:
2609 GroupName (str): Name of a PyMOL group.
2610 GroupMembersList (list): List of group member names.
2611 Enable (bool): Display status of group.
2612 Action (str): Open or close status of group object.
2613
2614 Returns:
2615 str: PML commands for creating a group object.
2616
2617 """
2618
2619 PMLCmds = []
2620
2621 GroupMembers = " ".join(GroupMembersList)
2622 PMLCmds.append("""cmd.group("%s", "%s")""" % (GroupName, GroupMembers))
2623
2624 if Enable is not None:
2625 if Enable:
2626 PMLCmds.append("""cmd.enable("%s")""" % GroupName)
2627 else:
2628 PMLCmds.append("""cmd.disable("%s")""" % GroupName)
2629
2630 if Action is not None:
2631 PMLCmds.append("""cmd.group("%s", action="%s")""" % (GroupName, Action))
2632
2633 PML = "\n".join(PMLCmds)
2634
2635 return PML
2636
2637
2638 def SetupPMLForLigandView(Name, Selection, LigandResName, Enable=True, IgnoreHydrogens=False):
2639 """Setup PML commands for creating a ligand view corresponding to a ligand
2640 present in a selection. The ligand is identified using organic selection
2641 operator available in PyMOL in conjunction with the specified ligand ID.
2642 The ligand is colored by atom types and displayed as 'sticks'.
2643
2644 Arguments:
2645 Name (str): Name of a new PyMOL ligand object.
2646 Selection (str): PyMOL selection containing ligand.
2647 LigandResName (str): Ligand ID.
2648 Enable (bool): Display status of ligand object.
2649 IgnoreHydrogens (bool): Ignore hydrogens.
2650
2651 Returns:
2652 str: PML commands for a ligand view.
2653
2654 """
2655
2656 PMLCmds = []
2657
2658 IgnoreHydrogensClause = " and (not hydro)" if IgnoreHydrogens else ""
2659 PMLCmds.append(
2660 """cmd.create("%s", "((%s) and organic and (resn %s)%s)")"""
2661 % (Name, Selection, LigandResName, IgnoreHydrogensClause)
2662 )
2663
2664 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
2665 PMLCmds.append("""util.cbag("%s", _self = cmd)""" % (Name))
2666 PMLCmds.append("""cmd.show("sticks", "%s")""" % (Name))
2667 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2668
2669 PML = "\n".join(PMLCmds)
2670
2671 return PML
2672
2673
2674 def SetupPMLForLigandsInputFileView(Name, InputFile, Enable=True, IgnoreHydrogens=False):
2675 """Setup PML commands for creating a ligand view corresponding to ligands
2676 present in a SD file. The ligand is colored by atom types and displayed as 'sticks'.
2677
2678 Arguments:
2679 Name (str): Name of a new PyMOL ligand(s) object.
2680 InputFile (str): Name of input file.
2681 Enable (bool): Display status of ligand object.
2682 IgnoreHydrogens (bool): Ignore hydrogens.
2683
2684 Returns:
2685 str: PML commands for a ligand view.
2686
2687 """
2688
2689 PMLCmds = []
2690
2691 PMLCmds.append("""cmd.load("%s", "%s")""" % (InputFile, Name))
2692
2693 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
2694 PMLCmds.append("""util.cbag("%s", _self = cmd)""" % (Name))
2695 PMLCmds.append("""cmd.show("sticks", "%s")""" % (Name))
2696 if IgnoreHydrogens:
2697 PMLCmds.append("""cmd.remove("(%s and hydro)")""" % (Name))
2698
2699 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2700
2701 PML = "\n".join(PMLCmds)
2702
2703 return PML
2704
2705
2706 def SetupPMLForLigandPocketView(Name, Selection, LigandSelection, DistanceCutoff, Enable=True, IgnoreHydrogens=False):
2707 """Setup PML commands for creating a ligand binding pocket view
2708 corresponding all residues present in a selection within a specified
2709 distance from a ligand selection. The solvent and inorganic portions of
2710 the selection are not included in the binding pocket. The pocket residues
2711 are shown as 'lines'. The hydrogen atoms are not displayed.
2712
2713 Arguments:
2714 Name (str): Name of a new PyMOL binding pocket object.
2715 Selection (str): PyMOL selection containing binding pocket residues.
2716 LigandSelection (str): PyMOL selection containing ligand.
2717 DistanceCutoff (float): Distance cutoff from ligand for selecting
2718 binding pockect residues.
2719 Enable (bool): Display status of binding pocket object.
2720 IgnoreHydrogens (bool): Ignore hydrogens.
2721
2722 Returns:
2723 str: PML commands for a ligand binding pocket view.
2724
2725 """
2726
2727 PMLCmds = []
2728
2729 IgnoreHydrogensClause = " and (not hydro)" if IgnoreHydrogens else ""
2730 PMLCmds.append(
2731 """cmd.create("%s", "((byresidue (%s) within %.1f of (%s)) and (not solvent) and (not inorganic) and (not organic)%s)")"""
2732 % (Name, Selection, DistanceCutoff, LigandSelection, IgnoreHydrogensClause)
2733 )
2734
2735 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
2736 PMLCmds.append("""cmd.show("lines", "(%s)")""" % (Name))
2737 PMLCmds.append("""cmd.hide("(%s and hydro)")""" % (Name))
2738 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2739
2740 PML = "\n".join(PMLCmds)
2741
2742 return PML
2743
2744
2745 def SetupPMLForLigandPocketSolventView(Name, Selection, LigandSelection, DistanceCutoff, Enable=True):
2746 """Setup PML commands for creating a ligand binding pocket view
2747 corresponding to only solvent residues present in a selection within a
2748 specified distance from a ligand selection. The solvent pocket residues
2749 are shown as 'lines' and 'nonbonded'.
2750
2751 Arguments:
2752 Name (str): Name of a new PyMOL solvent binding pocket object.
2753 Selection (str): PyMOL selection containing binding pocket residues.
2754 LigandSelection (str): PyMOL selection containing ligand.
2755 DistanceCutoff (float): Distance cutoff from ligand for selecting
2756 binding pocket solvent residues.
2757 Enable (bool): Display status of binding pocket object.
2758
2759 Returns:
2760 str: PML commands for a ligand binding pocket view only showing solvent
2761 residues.
2762
2763 """
2764
2765 PMLCmds = []
2766 PMLCmds.append(
2767 """cmd.create("%s", "((byresidue (%s) within %.1f of (%s)) and solvent)")"""
2768 % (Name, Selection, DistanceCutoff, LigandSelection)
2769 )
2770 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
2771 PMLCmds.append("""cmd.show("nonbonded", "%s")""" % (Name))
2772 PMLCmds.append("""cmd.show("lines", "%s")""" % (Name))
2773 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2774
2775 PML = "\n".join(PMLCmds)
2776
2777 return PML
2778
2779
2780 def SetupPMLForLigandPocketInorganicView(Name, Selection, LigandSelection, DistanceCutoff, Enable=True):
2781 """Setup PML commands for creating a ligand binding pocket view
2782 corresponding to only inorganic residues present in a selection within a
2783 specified distance from a ligand selection. The inorganic pocket residues
2784 are shown as 'lines' and 'nonbonded'.
2785
2786 Arguments:
2787 Name (str): Name of a new PyMOL solvent binding pocket object.
2788 Selection (str): PyMOL selection containing binding pocket residues.
2789 LigandSelection (str): PyMOL selection containing ligand.
2790 DistanceCutoff (float): Distance cutoff from ligand for selecting
2791 binding pocket inorganic residues.
2792 Enable (bool): Display status of binding pocket object.
2793
2794 Returns:
2795 str: PML commands for a ligand binding pocket view only showing inorganic
2796 residues.
2797
2798 """
2799
2800 PMLCmds = []
2801 PMLCmds.append(
2802 """cmd.create("%s", "((byresidue (%s) within %.1f of (%s)) and inorganic)")"""
2803 % (Name, Selection, DistanceCutoff, LigandSelection)
2804 )
2805 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
2806 PMLCmds.append("""cmd.show("nonbonded", "%s")""" % (Name))
2807 PMLCmds.append("""cmd.show("lines", "%s")""" % (Name))
2808 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2809
2810 PML = "\n".join(PMLCmds)
2811
2812 return PML
2813
2814
2815 def SetupPMLForDistanceContactsView(
2816 Name, Selection1, Selection2, Enable=True, Color="yellow", Cutoff=None, IgnoreHydrogens=True
2817 ):
2818 """Setup PML commands for creating distance contacts view between a pair of
2819 selections. The distance contact view is generated using 'cmd.distance' command.
2820 The distance labels are shown by default.
2821
2822 Arguments:
2823 Name (str): Name of a new PyMOL distance contacts object.
2824 Selection1 (str): First PyMOL selection.
2825 Selection2 (str): Second PyMOL selection.
2826 Enable (bool): Display status of distance contacts object.
2827 Color (str): Color for distance contact lines and labels.
2828 DistanceCutoff (float): None or distance cutoff for distance contacts.
2829 IgnoreHydrogens (bool): Ignore hydrogens for distance contacts.
2830
2831 Returns:
2832 str: PML commands for distance contacts view between a pair of selections.
2833
2834 """
2835
2836 if IgnoreHydrogens:
2837 Selection1 = "(%s) and (not hydro)" % Selection1
2838 Selection2 = "(%s) and (not hydro)" % Selection2
2839
2840 PMLCmds = []
2841 if Cutoff is None:
2842 PMLCmds.append(
2843 """cmd.distance("%s","(%s)","(%s)", quiet = 1, mode = 0, label = 1, reset = 1)"""
2844 % (Name, Selection1, Selection2)
2845 )
2846 else:
2847 PMLCmds.append(
2848 """cmd.distance("%s","(%s)","(%s)", cutoff = %.1f, quiet = 1, mode = 0, label = 1, reset = 1)"""
2849 % (Name, Selection1, Selection2, Cutoff)
2850 )
2851
2852 PMLCmds.append(SetupPMLForDeepColoring(Name, Color))
2853 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2854
2855 PML = "\n".join(PMLCmds)
2856
2857 return PML
2858
2859
2860 def SetupPMLForHalogenContactsView(
2861 Name, Selection1, Selection2, Enable=True, Color="magenta", Cutoff=None, IgnoreHydrogens=True
2862 ):
2863 """Setup PML commands for creating halogen distance contacts view between a
2864 pair of selections. The Selection1 corresponds to the selection containing halogens.
2865 The halogen contact view is generated using 'cmd.distance' command. The
2866 distance labels are shown by default.
2867
2868 Arguments:
2869 Name (str): Name of a new PyMOL halogen contacts object.
2870 Selection1 (str): First PyMOL selection containing halogens.
2871 Selection2 (str): Second PyMOL selection.
2872 Enable (bool): Display status of halogen contacts object.
2873 Color (str): Color for halogen contact lines and labels.
2874 DistanceCutoff (float): None or distance cutoff for distance contacts.
2875 IgnoreHydrogens (bool): Ignore hydrogens for halogen contacts.
2876
2877 Returns:
2878 str: PML commands for halogen contacts view between a pair of selections.
2879
2880 """
2881
2882 HalogenSelection1 = "(%s) and (elem F,Cl,Br,I)" % Selection1
2883
2884 return SetupPMLForDistanceContactsView(Name, HalogenSelection1, Selection2, Enable, Color, Cutoff)
2885
2886
2887 def SetupPMLForPiPiContactsView(Name, Selection1, Selection2, Enable=True, Color="yellow", Cutoff=None):
2888 """Setup PML commands for creating pi pi contacts view between a pair of
2889 selections. The pi pi contact view is generated using 'cmd.distance' command
2890 with support for mode 6 and may require incentive version of PyMOL. The
2891 distance labels are shown by default.
2892
2893 Arguments:
2894 Name (str): Name of a new PyMOL pi pi contacts object.
2895 Selection1 (str): First PyMOL selection.
2896 Selection2 (str): Second PyMOL selection.
2897 Enable (bool): Display status of pi pi contacts object.
2898 Color (str): Color for pi pi contact lines and labels.
2899 DistanceCutoff (float): None or distance cutoff for pi pi contacts.
2900
2901 Returns:
2902 str: PML commands for pi pi contacts view between a pair of selections.
2903
2904 """
2905
2906 Mode = 6
2907 return _SetupPMLForPiContactsView(Name, Selection1, Selection2, Mode, Enable, Color, Cutoff)
2908
2909
2910 def SetupPMLForPiCationContactsView(Name, Selection1, Selection2, Enable=True, Color="yellow", Cutoff=None):
2911 """Setup PML commands for creating pi cation contacts view between a pair of
2912 selections. The pi pi contact view is generated using 'cmd.distance' command
2913 with support for mode 7 and may require incentive version of PyMOL. The
2914 distance labels are shown by default.
2915
2916 Arguments:
2917 Name (str): Name of a new PyMOL pi cation contacts object.
2918 Selection1 (str): First PyMOL selection.
2919 Selection2 (str): Second PyMOL selection.
2920 Enable (bool): Display status of pi cation contacts object.
2921 Color (str): Color for pi pi contact lines and labels.
2922 DistanceCutoff (float): None or distance cutoff for pi cation contacts.
2923
2924 Returns:
2925 str: PML commands for pi pi contacts view between a pair of selections.
2926
2927 """
2928
2929 Mode = 7
2930 return _SetupPMLForPiContactsView(Name, Selection1, Selection2, Mode, Enable, Color, Cutoff)
2931
2932
2933 def _SetupPMLForPiContactsView(Name, Selection1, Selection2, Mode, Enable=True, Color="yellow", Cutoff=None):
2934 """Setup PML commands for creating pi pi or pi cation contacts view between a
2935 selections. The pi pi and pi cation contact views are generated using 'cmd.distance'
2936 command.
2937 """
2938
2939 PMLCmds = []
2940 if Cutoff is None:
2941 PMLCmds.append(
2942 """cmd.distance("%s","(%s)","(%s)", quiet = 1, mode = %s, label = 1, reset = 1)"""
2943 % (Name, Selection1, Selection2, Mode)
2944 )
2945 else:
2946 PMLCmds.append(
2947 """cmd.distance("%s","(%s)","(%s)", cutoff = %.1f, quiet = 1, mode = %s, label = 1, reset = 1)"""
2948 % (Name, Selection1, Selection2, Cutoff, Mode)
2949 )
2950
2951 PMLCmds.append(SetupPMLForDeepColoring(Name, Color))
2952 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2953
2954 PML = "\n".join(PMLCmds)
2955
2956 return PML
2957
2958
2959 def SetupPMLForPolarContactsView(Name, Selection1, Selection2, Enable=True, Color="yellow", Cutoff=None):
2960 """Setup PML commands for creating polar contacts view between a pair of
2961 selections. The polar contact view is generated using 'cmd.dist' command. The
2962 distance labels are shown by default.
2963
2964 Arguments:
2965 Name (str): Name of a new PyMOL polar contacts object.
2966 Selection1 (str): First PyMOL selection.
2967 Selection2 (str): Second PyMOL selection.
2968 Enable (bool): Display status of polar contacts object.
2969 Color (str): Color for polar contact lines and labels.
2970 DistanceCutoff (float): None or distance cutoff for polar contacts.
2971
2972 Returns:
2973 str: PML commands for polar contacts view between a pair of selections.
2974
2975 """
2976
2977 PMLCmds = []
2978 if Cutoff is None:
2979 PMLCmds.append(
2980 """cmd.distance("%s","(%s)","(%s)", quiet = 1, mode = 2, label = 1, reset = 1)"""
2981 % (Name, Selection1, Selection2)
2982 )
2983 else:
2984 PMLCmds.append(
2985 """cmd.distance("%s","(%s)","(%s)", cutoff = %.1f, quiet = 1, mode = 2, label = 1, reset = 1)"""
2986 % (Name, Selection1, Selection2, Cutoff)
2987 )
2988
2989 PMLCmds.append(SetupPMLForDeepColoring(Name, Color))
2990 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
2991
2992 PML = "\n".join(PMLCmds)
2993
2994 return PML
2995
2996
2997 def SetupPMLForHydrophobicContactsView(Name, Selection1, Selection2, Enable=True, Color="yellow", Cutoff=None):
2998 """Setup PML commands for creating hydrophobic contacts view between a pair of
2999 selections. The hydrophobic contacts are shown between pairs of carbon atoms not
3000 connected to hydrogen bond donor or acceptors atoms as identified by PyMOL. The
3001 distance labels are shown by default.
3002
3003 Arguments:
3004 Name (str): Name of a new PyMOL polar contacts object.
3005 Selection1 (str): First PyMOL selection.
3006 Selection2 (str): Second PyMOL selection.
3007 Enable (bool): Display status of polar contacts object.
3008 Color (str): Color for polar contact lines and labels.
3009 Cutoff (float): None or distance cutoff for hydrophobic contacts.
3010
3011 Returns:
3012 str: PML commands for polar contacts view between a pair of selections.
3013
3014 """
3015
3016 PMLCmds = []
3017
3018 HydrophobicSelectionAtoms1 = "((%s) and (elem C) and (not bound_to (donors or acceptors)))" % (Selection1)
3019 HydrophobicSelectionAtoms2 = "((%s) and (elem C) and (not bound_to (donors or acceptors)))" % (Selection2)
3020
3021 if Cutoff is None:
3022 PMLCmds.append(
3023 """cmd.distance("%s","(%s)","(%s)", quiet = 1, mode = 0, label = 1, reset = 1)"""
3024 % (Name, HydrophobicSelectionAtoms1, HydrophobicSelectionAtoms2)
3025 )
3026 else:
3027 PMLCmds.append(
3028 """cmd.distance("%s","(%s)","(%s)", cutoff = %.1f, quiet = 1, mode = 0, label = 1, reset = 1)"""
3029 % (Name, HydrophobicSelectionAtoms1, HydrophobicSelectionAtoms2, Cutoff)
3030 )
3031
3032 PMLCmds.append(SetupPMLForDeepColoring(Name, Color))
3033 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3034
3035 PML = "\n".join(PMLCmds)
3036
3037 return PML
3038
3039
3040 def SetupPMLForDeepColoring(Name, Color):
3041 """Setup PML command for deep coloring based on PyMOL version number.
3042
3043 Arguments:
3044 Name (str): Name of a PyMOL object.
3045 Color (str): Color for PyMOL object.
3046
3047 Returns:
3048 str: PML command for deep coloring.
3049
3050 """
3051
3052 if cmd.get_version()[1] < 2.0:
3053 return """util.color_deep("%s", "%s")""" % (Color, Name)
3054 else:
3055 return """cmd.color_deep("%s", "%s")""" % (Color, Name)
3056
3057
3058 def SetupPMLForAlignment(Method, RefSelection, FitSelection):
3059 """Setup PML commands for aligning a pair of selection using a specified
3060 alignment method.
3061
3062 Arguments:
3063 Name (str): Name of a PyMOL object.
3064
3065 Returns:
3066 str: PML commands for aligning a pair of selections.
3067
3068 """
3069
3070 PMLCmds = []
3071 if re.match("^align$", Method, re.I):
3072 PMLCmds.append("""cmd.align("(%s)", "(%s)")""" % (FitSelection, RefSelection))
3073 elif re.match("^cealign$", Method, re.I):
3074 PMLCmds.append("""cmd.cealign("(%s)", "(%s)")""" % (RefSelection, FitSelection))
3075 elif re.match("^super$", Method, re.I):
3076 PMLCmds.append("""cmd.super("(%s)", "(%s)")""" % (FitSelection, RefSelection))
3077 else:
3078 MiscUtil.PrintWarning("PyMOLUtil.SetupPMLForAlignment: Invalid method name: %s" % Method)
3079
3080 PML = "\n".join(PMLCmds)
3081
3082 return PML
3083
3084
3085 def SetupPMLForBFactorCartoonView(Name, Selection, ColorPalette="blue_white_red", Enable=True):
3086 """Setup PML commands for creating a B factor cartoon view for a specified
3087 selection. The B factor values must be available for the atoms. The atoms
3088 are colored using a color spectrum corresponding to a specified color
3089 palette. Any valid PyMOL color palette name may be used.
3090
3091 Arguments:
3092 Name (str): Name of a new PyMOL B factor cartoon object.
3093 Selection (str): Name of PyMOL selection.
3094 ColorPalette (str): Name of color palette to use for color spectrum.
3095 Enable (bool): Display status of B factor putty object.
3096
3097 Returns:
3098 str: PML commands for B factor putty view.
3099
3100 """
3101
3102 return _SetupPMLForBFactorView(Name, Selection, ColorPalette, Enable, Putty=False)
3103
3104
3105 def SetupPMLForBFactorPuttyView(Name, Selection, ColorPalette="blue_white_red", Enable=True):
3106 """Setup PML commands for creating a B factor putty view for a specified
3107 selection. The B factor values must be available for the atoms. The atoms
3108 are colored using a color spectrum corresponding to a specified color
3109 palette. Any valid PyMOL color palette name may be used.
3110
3111 Arguments:
3112 Name (str): Name of a new PyMOL B factor putty object.
3113 Selection (str): Name of PyMOL selection.
3114 ColorPalette (str): Name of color palette to use for color spectrum.
3115 Enable (bool): Display status of B factor putty object.
3116
3117 Returns:
3118 str: PML commands for B factor putty view.
3119
3120 """
3121
3122 return _SetupPMLForBFactorView(Name, Selection, ColorPalette, Enable, Putty=True)
3123
3124
3125 def _SetupPMLForBFactorView(Name, Selection, ColorPalette="blue_white_red", Enable=True, Putty=True):
3126 """Setup PML commands for creating a B factor cartoon or putty view for a
3127 specified selection. The B factor values must be available for the atoms.
3128 """
3129
3130 PMLCmds = []
3131 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, Selection))
3132 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3133 PMLCmds.append("""cmd.spectrum("b", "%s", "(%s)")""" % (ColorPalette, Name))
3134 PMLCmds.append("""cmd.show("cartoon", "%s")""" % (Name))
3135 if Putty:
3136 PMLCmds.append("""cmd.cartoon("putty", "%s")""" % (Name))
3137 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3138
3139 PML = "\n".join(PMLCmds)
3140
3141 return PML
3142
3143
3144 def SetupPMLForHydrophobicSurfaceView(Name, Selection, ColorPalette="RedToWhite", Enable=True, DisplayAs="cartoon"):
3145 """Setup PML commands for creating a hydrophobic surface view for a specified
3146 selection. The surfaces are colored using a specified color palette. This is only valid
3147 for amino acids.
3148
3149 Arguments:
3150 Name (str): Name of a new PyMOL hydrophobic surface object.
3151 Selection (str): Name of PyMOL selection.
3152 ColorPalette (str): Name of color palette to use for coloring surfaces.
3153 Possible values: RedToWhite or WhiteToGreen for most hydrophobic
3154 to least hydrophobic amino acids.
3155 Enable (bool): Display status of surface object.
3156 DisplayAs (str): Any additional valid display type such as lines,
3157 sticks, ribbon, cartoon, or None.
3158
3159 Returns:
3160 str: PML commands for hydrophobic surface view.
3161
3162 """
3163
3164 PMLCmds = _GetPMLCmdsForSurfaceView(Name, Selection, DisplayAs)
3165 PMLCmds.append("""ColorByHydrophobicity("%s", "%s")""" % (Name, ColorPalette))
3166 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3167
3168 PML = "\n".join(PMLCmds)
3169
3170 return PML
3171
3172
3173 def SetupPMLForHydrophobicAndChargeSurfaceView(
3174 Name,
3175 Selection,
3176 HydrophobicAtomsColor="yellow",
3177 NegativelyChargedAtomsColor="red",
3178 PositivelyChargedAtomsColor="blue",
3179 OtherAtomsColor="gray90",
3180 Enable=True,
3181 DisplayAs="cartoon",
3182 ):
3183 """Setup PML commands for creating a surface colored by hydrophobic and
3184 charge [ REF 140] properties of atoms in amino acids. The atom names in
3185 standard amino acid residues are used to identify atom types as shown below:
3186
3187 Hydrophobic: C atoms not bound to N or O atoms; NegativelyCharged: Side
3188 chain O atoms in ASP and GLU; PositivelyCharged: Side chain N atoms in
3189 ARG and LYS; Others: Remaining atoms in polar and other residues
3190
3191 The amino acid atom names to color specific atoms are taken from YRB.py
3192 script [ REF 140]. The color values may also be specified as comma delimited
3193 RGB triplets. For example: HydrophobicAtomsColor = "0.950 0.78 0.0",
3194 NegativelyChargedAtomsColor = "1.0 0.4 0.4", PositivelyChargedAtomsColor
3195 = "0.2 0.5 0.8", OtherAtomsColor = "0.95 0.95 0.95"
3196
3197 Arguments:
3198 Name (str): Name of a new PyMOL hydrophobic surface object.
3199 Selection (str): Name of PyMOL selection.
3200 HydrophobicAtomsColor (str): Color name or space delimited RGB values
3201 NegativelyChargedAtomsColor (str): Color name or space delimited RGB values
3202 PositivelyChargedAtomsColor (str): Color name or space delimited RGB values
3203 OtherAtomsColor (str): Color name or space delimited RGB values
3204 Enable (bool): Display status of surface object.
3205 DisplayAs (str): Any additional valid display type such as lines,
3206 sticks, ribbon, cartoon, or None.
3207
3208 Returns:
3209 str: PML commands for hydrophobic and charge surface view.
3210
3211 """
3212
3213 PMLCmds = _GetPMLCmdsForSurfaceView(Name, Selection, DisplayAs)
3214 PMLCmds.append(
3215 """ColorAtomsByHydrophobicityAndCharge("%s", "%s", "%s", "%s", "%s")"""
3216 % (Name, HydrophobicAtomsColor, NegativelyChargedAtomsColor, PositivelyChargedAtomsColor, OtherAtomsColor)
3217 )
3218 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3219
3220 PML = "\n".join(PMLCmds)
3221
3222 return PML
3223
3224
3225 def SetupPMLForSurfaceView(Name, Selection, Enable=True, DisplayAs="cartoon", Color="None"):
3226 """Setup PML commands for creating a molecular surface view for a specified
3227 selection.
3228
3229 Arguments:
3230 Name (str): Name of a new PyMOL molecular surface object.
3231 Selection (str): Name of PyMOL selection.
3232 Enable (bool): Display status of surface object.
3233 DisplayAs (str): Any additional valid display type such as lines,
3234 sticks, ribbon, cartoon, or None.
3235 Color (str): Surafce color.
3236
3237 Returns:
3238 str: PML commands for molecular surface view.
3239
3240 """
3241
3242 PMLCmds = _GetPMLCmdsForSurfaceView(Name, Selection, DisplayAs)
3243 if Color is not None:
3244 PMLCmds.append(SetupPMLForDeepColoring(Name, Color))
3245 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3246
3247 PML = "\n".join(PMLCmds)
3248
3249 return PML
3250
3251
3252 def _GetPMLCmdsForSurfaceView(Name, Selection, DisplayAs="cartoon"):
3253 """Setup PML command for surface view."""
3254
3255 PMLCmds = []
3256 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, Selection))
3257 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3258 if DisplayAs is not None:
3259 PMLCmds.append("""cmd.show("%s", "%s")""" % (DisplayAs, Name))
3260 PMLCmds.append("""cmd.show("surface", "%s")""" % (Name))
3261
3262 return PMLCmds
3263
3264
3265 def SetupPMLForSelectionDisplayView(Name, Selection, DisplayAs, Color=None, Enable=True, IgnoreHydrogens=False):
3266 """Setup PML commands for creating a specific molecular display view for a
3267 selection.
3268
3269 Arguments:
3270 Name (str): Name of a new PyMOL object.
3271 Selection (str): Name of PyMOL selection.
3272 DisplayAs (str): Any valid display type such as lines, sticks, ribbon,
3273 cartoon, or surface
3274 Color (str): Color name or use default color.
3275 Enable (bool): Display status of object.
3276 IgnoreHydrogens (bool): Ignore hydrogens.
3277
3278 Returns:
3279 str: PML commands for molecular selection view.
3280
3281 """
3282
3283 PMLCmds = []
3284 if IgnoreHydrogens:
3285 PMLCmds.append("""cmd.create("%s", "((%s) and (not hydro))")""" % (Name, Selection))
3286 else:
3287 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, Selection))
3288 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3289 PMLCmds.append("""cmd.show("%s", "%s")""" % (DisplayAs, Name))
3290 if Color is not None:
3291 PMLCmds.append(SetupPMLForDeepColoring(Name, Color))
3292 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3293
3294 PML = "\n".join(PMLCmds)
3295
3296 return PML
3297
3298
3299 def SetupPMLForBallAndStickView(Name, Selection, Enable=True, SphereScale=0.3, StickRadius=0.2):
3300 """Setup PML commands for creating a ball and stick view for a specified
3301 selection.
3302
3303 Arguments:
3304 Name (str): Name of a new PyMOL ball and stick object.
3305 Selection (str): Name of PyMOL selection.
3306 Enable (bool): Display status of ball and stick object.
3307 SphereScale (float): Scaling factor for sphere radii.
3308 StickScale (float): Scaling factor for stick radii.
3309
3310 Returns:
3311 str: PML commands for ball and stick view.
3312
3313 """
3314
3315 PMLCmds = []
3316 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, Selection))
3317 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3318 PMLCmds.append("""cmd.show("sphere", "%s")""" % (Name))
3319 PMLCmds.append("""cmd.show("sticks", "%s")""" % (Name))
3320 PMLCmds.append("""cmd.set("sphere_scale", %.1f, "%s")""" % (SphereScale, Name))
3321 PMLCmds.append("""cmd.set("stick_radius", %.1f, "%s")""" % (StickRadius, Name))
3322
3323 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3324
3325 PML = "\n".join(PMLCmds)
3326
3327 return PML
3328
3329
3330 def SetupPMLForInorganicView(Name, Selection, Enable=True):
3331 """Setup PML commands for creating a inorganic view corresponding to
3332 inorganic residues present in a selection. The inorganic residues are
3333 identified using inorganic selection operator available in PyMOL. The
3334 inorganic residues are displayed as 'lines' and 'nonbonded'.
3335
3336 Arguments:
3337 Name (str): Name of a new PyMOL inorganic object.
3338 Selection (str): Name of PyMOL selection.
3339 Enable (bool): Display status of inorganic object.
3340
3341 Returns:
3342 str: PML commands for inorganic view.
3343
3344 """
3345
3346 PMLCmds = []
3347 PMLCmds.append("""cmd.create("%s", "((%s) and inorganic)")""" % (Name, Selection))
3348 PMLCmds.append("""cmd.show("nonbonded", "%s")""" % (Name))
3349 PMLCmds.append("""cmd.show("lines", "%s")""" % (Name))
3350 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3351
3352 PML = "\n".join(PMLCmds)
3353
3354 return PML
3355
3356
3357 def SetupPMLForSolventView(Name, Selection, Enable=True):
3358 """Setup PML commands for creating a solvent view corresponding to
3359 solvent residues present in a selection. The solvent residues are
3360 identified using solvent selection operator available in PyMOL. The
3361 solvent residues are displayed as 'nonbonded'.
3362
3363 Arguments:
3364 Name (str): Name of a new PyMOL solvent object.
3365 Selection (str): Name of PyMOL selection.
3366 Enable (bool): Display status of inorganic object.
3367
3368 Returns:
3369 str: PML commands for solvent view.
3370
3371 """
3372
3373 PMLCmds = []
3374 PMLCmds.append("""cmd.create("%s", "((%s) and solvent)")""" % (Name, Selection))
3375 PMLCmds.append("""cmd.show("nonbonded", "%s")""" % (Name))
3376 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3377
3378 PML = "\n".join(PMLCmds)
3379
3380 return PML
3381
3382
3383 def SetupPMLForDisulfideBondsView(Name, Selection, DisplayAs, Enable=True):
3384 """Setup PML commands for creating a view corresponding to
3385 disulfide bonds present in a selection.
3386
3387 Arguments:
3388 Name (str): Name of a new PyMOL disulfide bonds object.
3389 Selection (str): Name of PyMOL selection.
3390 DisplayAs (str): Any valid display type such as lines, sticks, ribbon,
3391 cartoon, or surface
3392 Enable (bool): Display status of disulfide bonds object.
3393
3394 Returns:
3395 str: PML commands for disulfide bonds view.
3396
3397 """
3398
3399 PMLCmds = []
3400
3401 DisulfideBondsSelection = (
3402 "(byres (((%s) and (resn CYS+CYX) and (name SG)) and bound_to ((%s) and (resn CYS+CYX) and (name SG))))"
3403 % (Selection, Selection)
3404 )
3405 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, DisulfideBondsSelection))
3406 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3407 PMLCmds.append("""util.cbag("%s", _self = cmd)""" % (Name))
3408 PMLCmds.append("""cmd.show("%s", "%s")""" % (DisplayAs, Name))
3409 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3410
3411 PML = "\n".join(PMLCmds)
3412
3413 return PML
3414
3415
3416 def SetupPMLForSaltBridgesResiduesView(Name, Selection, Residues, DisplayAs, Enable=True):
3417 """Setup PML commands for creating a view corresponding to residues
3418 for salt bridges present in a selection.
3419
3420 Arguments:
3421 Name (str): Name of a new PyMOL disulfide bonds object.
3422 Selection (str): Name of PyMOL selection.
3423 Residues (list): List of residues.
3424 DisplayAs (str): Any valid display type such as lines, sticks, ribbon,
3425 cartoon, or surface
3426 Enable (bool): Display status of salt bridges residues object.
3427
3428 Returns:
3429 str: PML commands for salt bridges residues view.
3430
3431 """
3432
3433 PMLCmds = []
3434
3435 SaltBridgesResiduesSelection = "((%s) and (resn %s) and (not name N+O) and (not hydro))" % (
3436 Selection,
3437 "+".join(Residues),
3438 )
3439
3440 PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, SaltBridgesResiduesSelection))
3441 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3442 PMLCmds.append("""util.cbag("%s", _self = cmd)""" % (Name))
3443 PMLCmds.append("""cmd.show("%s", "%s")""" % (DisplayAs, Name))
3444 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3445
3446 PML = "\n".join(PMLCmds)
3447
3448 return PML
3449
3450
3451 def SetupPMLForPolymerChainView(Name, Selection, Enable=True):
3452 """Setup PML commands for creating a polymer chain view corresponding
3453 to backbone and sidechain residues in a selection. The polymer chain is
3454 displayed as 'cartoon'.
3455
3456 Arguments:
3457 Name (str): Name of a new PyMOL polymer chain object.
3458 Selection (str): Name of PyMOL selection.
3459 Enable (bool): Display status of chain object.
3460
3461 Returns:
3462 str: PML commands for polymer chain view.
3463
3464 """
3465
3466 PMLCmds = []
3467 PMLCmds.append("""cmd.create("%s", "((%s) and (backbone or sidechain))")""" % (Name, Selection))
3468 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3469 PMLCmds.append("""util.cbag("%s", _self = cmd)""" % (Name))
3470 PMLCmds.append("""cmd.show("cartoon", "%s")""" % (Name))
3471 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3472
3473 PML = "\n".join(PMLCmds)
3474
3475 return PML
3476
3477
3478 def SetupPMLForPolymerComplexView(
3479 MoleculeName, PDBFile, Enable=True, ShowSolvent=True, ShowInorganic=True, ShowLines=True
3480 ):
3481 """Setup PML commands for creating a polymer complex view for all chains
3482 in a PDB file. The solvent and inorganic residues are also shown by default.
3483 The polymer chains are displayed as 'cartoon'. The 'line' display for the
3484 polymer chains is also shown and may be turned off. The organic residues are
3485 displayed as 'sticks'. The solvent and inorganic residues are displayed as
3486 'nonbonded' and 'lines'.
3487
3488 Arguments:
3489 MoleculeName (str): Name of a new PyMOL molecule object.
3490 PDBFile (str): Name of PDB file.
3491 Enable (bool): Display status of chain object.
3492 ShowSolvent (bool): Display solvent residues.
3493 ShowInorganic (bool): Display inorganic residues.
3494 ShowLines (bool): Display lines for polymer chains.
3495
3496 Returns:
3497 str: PML commands for polymer complex view.
3498
3499 """
3500
3501 PMLCmds = []
3502
3503 PMLCmds.append("""cmd.load("%s", "%s")""" % (PDBFile, MoleculeName))
3504 PML = _SetupPMLForPolymerComplexView(MoleculeName, Enable, ShowSolvent, ShowInorganic, ShowLines)
3505 PMLCmds.append(PML)
3506
3507 PML = "\n".join(PMLCmds)
3508
3509 return PML
3510
3511
3512 def SetupPMLForPolymerChainComplexView(
3513 ChainComplexName, Selection, ChainName, Enable=True, ShowSolvent=True, ShowInorganic=True, ShowLines=True
3514 ):
3515 """Setup PML commands for creating a polymer chain complex view for a specified
3516 chain in a selection. The solvent and inorganic residues are also shown by
3517 default. The polymer chain is displayed as 'cartoon'. The 'line' display for the
3518 polymer chain is also shown and may be turned off. The organic residues are
3519 displayed as 'sticks'. The solvent and inorganic residues are displayed as
3520 'nonbonded' and 'lines'.
3521
3522 Arguments:
3523 ChainComplexName (str): Name of a new PyMOL polymer chain complex.
3524 Selection (str): Name of PyMOL selection.
3525 ChainName (str): Name of a chain.
3526 Enable (bool): Display status of chain object.
3527 ShowSolvent (bool): Display solvent residues.
3528 ShowInorganic (bool): Display inorganic residues.
3529 ShowLines (bool): Display lines for polymer chain.
3530
3531 Returns:
3532 str: PML commands for polymer chain complex view.
3533
3534 """
3535
3536 PMLCmds = []
3537
3538 PMLCmds.append("""cmd.create("%s", "(%s and chain %s)")""" % (ChainComplexName, Selection, ChainName))
3539 PML = _SetupPMLForPolymerComplexView(ChainComplexName, Enable, ShowSolvent, ShowInorganic, ShowLines)
3540 PMLCmds.append(PML)
3541
3542 PML = "\n".join(PMLCmds)
3543
3544 return PML
3545
3546
3547 def _SetupPMLForPolymerComplexView(Name, Enable=True, ShowSolvent=True, ShowInorganic=True, ShowLines=False):
3548 """Setup PML for creating a polymer complex view."""
3549
3550 PMLCmds = []
3551
3552 PMLCmds.append("""cmd.hide("everything", "%s")""" % (Name))
3553 PMLCmds.append("""cmd.show("cartoon", "%s")""" % (Name))
3554 PMLCmds.append("""util.cba(33, "%s", _self = cmd)""" % (Name))
3555 PMLCmds.append("""cmd.show("sticks", "(organic and (%s))")""" % (Name))
3556 if ShowSolvent:
3557 PMLCmds.append("""cmd.show("nonbonded", "(solvent and (%s))")""" % (Name))
3558 if ShowInorganic:
3559 PMLCmds.append("""cmd.show("nonbonded", "(inorganic and (%s))")""" % (Name))
3560
3561 if ShowLines:
3562 PMLCmds.append("""cmd.show("lines", "%s")""" % (Name))
3563 else:
3564 if ShowInorganic:
3565 PMLCmds.append("""cmd.show("lines", "(inorganic and (%s))")""" % (Name))
3566
3567 PMLCmds.append("""cmd.set_bond("valence", "1", "%s", quiet = 1)""" % (Name))
3568 PMLCmds.append(SetupPMLForEnableDisable(Name, Enable))
3569
3570 PML = "\n".join(PMLCmds)
3571
3572 return PML