MayaChemTools

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