1 #!/bin/env python 2 # 3 # File: PyMOLGenerateRamachandranPlots.py 4 # Author: Manish Sud <msud@san.rr.com> 5 # 6 # Copyright (C) 2025 Manish Sud. All rights reserved. 7 # 8 # The functionality available in this script is implemented using PyMOL, a 9 # molecular visualization system on an open source foundation originally 10 # developed by Warren DeLano. 11 # 12 # This file is part of MayaChemTools. 13 # 14 # MayaChemTools is free software; you can redistribute it and/or modify it under 15 # the terms of the GNU Lesser General Public License as published by the Free 16 # Software Foundation; either version 3 of the License, or (at your option) any 17 # later version. 18 # 19 # MayaChemTools is distributed in the hope that it will be useful, but without 20 # any warranty; without even the implied warranty of merchantability of fitness 21 # for a particular purpose. See the GNU Lesser General Public License for more 22 # details. 23 # 24 # You should have received a copy of the GNU Lesser General Public License 25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 27 # Boston, MA, 02111-1307, USA. 28 # 29 30 from __future__ import print_function 31 32 # Add local python path to the global path and import standard library modules... 33 import os 34 import sys; sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python")) 35 import time 36 import re 37 import csv 38 import matplotlib.pyplot as plt 39 import numpy as np 40 41 # PyMOL imports... 42 try: 43 import pymol 44 # Finish launching PyMOL in a command line mode for batch processing (-c) 45 # along with the following options: disable loading of pymolrc and plugins (-k); 46 # suppress start up messages (-q) 47 pymol.finish_launching(['pymol', '-ckq']) 48 except ImportError as ErrMsg: 49 sys.stderr.write("\nFailed to import PyMOL module/package: %s\n" % ErrMsg) 50 sys.stderr.write("Check/update your PyMOL environment and try again.\n\n") 51 sys.exit(1) 52 53 # MayaChemTools imports... 54 try: 55 from docopt import docopt 56 import MiscUtil 57 import PyMOLUtil 58 except ImportError as ErrMsg: 59 sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg) 60 sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n") 61 sys.exit(1) 62 63 ScriptName = os.path.basename(sys.argv[0]) 64 Options = {} 65 OptionsInfo = {} 66 67 def main(): 68 """Start execution of the script.""" 69 70 MiscUtil.PrintInfo("\n%s (PyMOL v%s; MayaChemTools v%s; %s): Starting...\n" % (ScriptName, pymol.cmd.get_version()[0], MiscUtil.GetMayaChemToolsVersion(), time.asctime())) 71 72 (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime() 73 74 # Retrieve command line arguments and options... 75 RetrieveOptions() 76 77 # Process and validate command line arguments and options... 78 ProcessOptions() 79 80 # Perform actions required by the script... 81 GenerateRamachandranPlots() 82 83 MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName) 84 MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime)) 85 86 def GenerateRamachandranPlots(): 87 """Calculate phi and psi angles for macromolecules containing amino acids 88 and generate Ramachandran plots. 89 """ 90 91 # Calculate phi and psi angles.. 92 CalculatePhiPsiAngles() 93 94 # Read phi and psi densities... 95 ReadPhiAndPsiDensities() 96 97 # Setup contour info... 98 SetupContoursInfo() 99 100 # Generate plots... 101 if OptionsInfo["MultipleOutFiles"]: 102 GenerateMultiplePlotFiles() 103 else: 104 GenerateSinglePlotFile() 105 106 def GenerateSinglePlotFile(): 107 """Generate a single plot file containg all four types of Ramachandran plots.""" 108 109 Outfile = OptionsInfo["Outfile"] 110 MiscUtil.PrintInfo("\nGenerating output file %s..." % (Outfile)) 111 112 SetupFontFamily() 113 114 # Setup figure... 115 PlotFigure, Axes = plt.subplots(2, 2, figsize = (OptionsInfo["FigWidth"], OptionsInfo["FigHeight"]), dpi = OptionsInfo["FigDPI"]) 116 PlotAxes = [Axis for RowAxes in Axes for Axis in RowAxes] 117 118 # Adjust space between subplots... 119 plt.subplots_adjust(left = 0.1, right = 0.9, bottom = 0.1, top = 0.9, wspace = 0.3, hspace = 0.25) 120 121 for PlotIndex, PlotType in enumerate(OptionsInfo["PlotTypesInfo"]["Types"]): 122 DrawPlot(PlotAxes[PlotIndex], PlotType) 123 124 # Save figure... 125 plt.savefig(Outfile) 126 127 def GenerateMultiplePlotFiles(): 128 """Generate multiple plot files corresponding to four types of Ramachandran plots.""" 129 130 MiscUtil.PrintInfo("\nGenerating multiple output files...") 131 132 SetupFontFamily() 133 134 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 135 Outfile = OptionsInfo["PlotTypesInfo"]["Outfiles"][PlotType] 136 MiscUtil.PrintInfo("Generating output file %s..." % Outfile) 137 138 PlotFigure, PlotAxis = plt.subplots(1, 1, figsize = (OptionsInfo["FigWidth"], OptionsInfo["FigHeight"]), dpi = OptionsInfo["FigDPI"]) 139 DrawPlot(PlotAxis, PlotType) 140 141 # Save figure... 142 plt.savefig(Outfile) 143 144 # Get ready for the next figure... 145 plt.clf() 146 147 def DrawPlot(PlotAxis, PlotType): 148 """Draw contour and scatter plot.""" 149 150 PlotTypesInfo = OptionsInfo["PlotTypesInfo"] 151 152 # Draw filled contours... 153 PhiPsiContourInfo = PlotTypesInfo["PhiPsiContourInfo"][PlotType] 154 PlotAxis.contourf(PhiPsiContourInfo["X"], PhiPsiContourInfo["Y"], PhiPsiContourInfo["Z"], levels = PlotTypesInfo["Levels"][PlotType], colors = PlotTypesInfo["Colors"][PlotType]) 155 156 # Draw scatter plot for phi and psi angles... 157 if PlotTypesInfo["ResCount"][PlotType]: 158 PlotAxis.scatter(PlotTypesInfo["PhiAngles"][PlotType], PlotTypesInfo["PsiAngles"][PlotType], s = OptionsInfo["ScatterMarkerSize"], c = OptionsInfo["ScatterMarkerColor"], marker = OptionsInfo["ScatterMarkerStyle"]) 159 160 # Setup limits... 161 PlotAxis.set_xlim(PlotTypesInfo["Limits"][PlotType]) 162 PlotAxis.set_ylim(PlotTypesInfo["Limits"][PlotType]) 163 164 # Setup major tick marks... 165 PlotAxis.set_xticklabels(PlotTypesInfo["MajorTickLabels"][PlotType], fontdict = {"fontsize": OptionsInfo["FontTicksSize"], "fontweight": OptionsInfo["FontTicksWeight"]}) 166 PlotAxis.set_xticks(PlotTypesInfo["MajorTickPositions"][PlotType]) 167 PlotAxis.set_yticklabels(PlotTypesInfo["MajorTickLabels"][PlotType], fontdict = {"fontsize": OptionsInfo["FontTicksSize"], "fontweight": OptionsInfo["FontTicksWeight"]}) 168 PlotAxis.set_yticks(PlotTypesInfo["MajorTickPositions"][PlotType]) 169 170 # Set up minor ticks... 171 if OptionsInfo["TicksMinor"]: 172 PlotAxis.set_xticks(PlotTypesInfo["MinorTickPositions"][PlotType], minor = True) 173 PlotAxis.set_yticks(PlotTypesInfo["MinorTickPositions"][PlotType], minor = True) 174 175 # Setup grid... 176 if OptionsInfo["Grid"]: 177 PlotAxis.grid(True, color = OptionsInfo["GridLineColor"], linestyle = OptionsInfo["GridLineStyle"], linewidth = OptionsInfo["GridLineWidth"]) 178 179 # Setup title... 180 PlotAxis.set_title(PlotTypesInfo["Titles"][PlotType], fontsize = OptionsInfo["FontTitleSize"], fontweight = OptionsInfo["FontTitleWeight"]) 181 182 # Setup axes labels... 183 if PlotTypesInfo["DrawXLabel"][PlotType]: 184 XLabel = r"$\Phi$" if OptionsInfo["Greek"] else "Phi" 185 PlotAxis.set_xlabel(XLabel, fontsize = OptionsInfo["FontAxesSize"], fontweight = OptionsInfo["FontAxesWeight"]) 186 if PlotTypesInfo["DrawYLabel"][PlotType]: 187 # Setup a horizontal ylabel close to the axis... 188 YLabel = r"$\Psi$" if OptionsInfo["Greek"] else "Psi" 189 YRotation = 0 if OptionsInfo["Greek"] else 90 190 PlotAxis.set_ylabel(YLabel, fontsize = OptionsInfo["FontAxesSize"], fontweight = OptionsInfo["FontAxesWeight"], rotation = YRotation, labelpad = 0) 191 192 def SetupFontFamily(): 193 """Setuo global font family.""" 194 195 if re.match("^auto$", OptionsInfo["FontFamily"], re.I): 196 return 197 plt.rcParams["font.family"] = OptionsInfo["FontFamily"] 198 199 def SetupContoursInfo(): 200 """Setup contour info for generating contour plots.""" 201 202 MiscUtil.PrintInfo("\nProcessing phi and psi densities for contour plots...") 203 204 OptionsInfo["PlotTypesInfo"]["PhiPsiContourInfo"] = {} 205 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 206 PhiPsiContourInfo = SetupPhiAndPsiContourInfo(PlotType) 207 OptionsInfo["PlotTypesInfo"]["PhiPsiContourInfo"][PlotType] = PhiPsiContourInfo 208 209 def SetupPhiAndPsiContourInfo(PlotType): 210 """Setup X, Y and Z contour arrays for generating contour plots.""" 211 212 DensityInfo = OptionsInfo["PlotTypesInfo"]["PhiPsiDensityInfo"][PlotType] 213 214 X, Y = np.meshgrid(DensityInfo["PhiValues"], DensityInfo["PsiValues"]) 215 Z = np.zeros((len(DensityInfo["PhiValues"]), len(DensityInfo["PsiValues"]))) 216 217 # Initialize X, Y, and Z arrays for contour plots... 218 for ZRowIndex, PsiID in enumerate(DensityInfo["PhiIDs"]): 219 for ZColIndex, PhiID in enumerate(DensityInfo["PsiIDs"]): 220 Z[ZRowIndex][ZColIndex] = DensityInfo["Density"][PhiID][PsiID] 221 222 # Track contour data... 223 ContourInfo = {} 224 ContourInfo["X"] = X 225 ContourInfo["Y"] = Y 226 ContourInfo["Z"] = Z 227 228 return ContourInfo 229 230 def ReadPhiAndPsiDensities(): 231 """Read phi and psi densities for generating filled contours.""" 232 233 OptionsInfo["PlotTypesInfo"]["PhiPsiDensityInfo"] = {} 234 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 235 DensityFile = OptionsInfo["PlotTypesInfo"]["PhiPsiDensityFiles"][PlotType] 236 PhiPsiDensityInfo = ReadPhiAndPsiDensityFile(DensityFile) 237 OptionsInfo["PlotTypesInfo"]["PhiPsiDensityInfo"][PlotType] = PhiPsiDensityInfo 238 239 def ReadPhiAndPsiDensityFile(DensityFile): 240 """Read phi and psi desnsity file. 241 242 Format: 243 Phi,Psi,Density 244 -179.0,-179.0,0.00782923406455425 245 -179.0,-177.0,0.00641357067237856 246 ... ... ... 247 """ 248 249 MiscUtil.PrintInfo("\nReading psi and psi density grid file %s..." % DensityFile) 250 251 DensityFH = open(DensityFile, "r") 252 if DensityFH is None: 253 MiscUtil.PrintError("Couldn't open phi and psi density file: %s.\n" % (DensityFile)) 254 255 HeaderLine = True 256 DensityLines = [] 257 for Line in DensityFH: 258 Line = Line.rstrip() 259 # Ignore comments... 260 if re.match("^#", Line, re.I): 261 continue 262 # Ignore header line... 263 if HeaderLine: 264 HeaderLine = False 265 continue 266 DensityLines.append(Line) 267 268 DensityInfo = {} 269 DensityInfo["Density"] = {} 270 271 DensityInfo["PhiIDs"] = [] 272 DensityInfo["PhiValues"] = [] 273 274 DensityInfo["PsiIDs"] = [] 275 DensityInfo["PsiValues"] = [] 276 277 PhiValuesMap = {} 278 PsiValuesMap = {} 279 280 Count = 0 281 MinDensity = 99999.0 282 MaxDensity = - MinDensity 283 284 DensityReader = csv.reader(DensityLines, delimiter=',', quotechar='"') 285 for LineWords in DensityReader: 286 Count += 1 287 288 Phi = LineWords[0] 289 Psi = LineWords[1] 290 Density = LineWords[2] 291 292 # Track unique phi and psi value... 293 if not Phi in PhiValuesMap: 294 PhiValuesMap[Phi] = float(Phi) 295 if not Psi in PsiValuesMap: 296 PsiValuesMap[Psi] = float(Psi) 297 298 # Track density data... 299 if not Phi in DensityInfo["Density"]: 300 DensityInfo["Density"][Phi] = {} 301 302 Density = float(Density) 303 DensityInfo["Density"][Phi][Psi] = Density 304 if Density < MinDensity: 305 MinDensity = Density 306 if Density > MaxDensity: 307 MaxDensity = Density 308 309 # Sort and track values for phi and psi angles... 310 DensityInfo["PhiIDs"] = sorted(PhiValuesMap.keys(), key = lambda Phi: PhiValuesMap[Phi]) 311 DensityInfo["PhiValues"] = [PhiValuesMap[Phi] for Phi in DensityInfo["PhiIDs"]] 312 313 DensityInfo["PsiIDs"] = sorted(PsiValuesMap.keys(), key = lambda Psi: PsiValuesMap[Psi]) 314 DensityInfo["PsiValues"] = [PsiValuesMap[Psi] for Psi in DensityInfo["PsiIDs"]] 315 316 MiscUtil.PrintInfo("Minimum density: %.4f; Maximum density: %.4f" % (MinDensity, MaxDensity)) 317 MiscUtil.PrintInfo("Number of phi and psi angles: %s" % Count) 318 319 MiscUtil.PrintInfo("\nDimensions of phi and psi grid angles:") 320 MiscUtil.PrintInfo("Phi - Min: %s; Max: %s; Bin size: %s; Count: %s" % (DensityInfo["PhiValues"][0], DensityInfo["PhiValues"][-1], abs(DensityInfo["PhiValues"][1] - DensityInfo["PhiValues"][0]), len(DensityInfo["PhiValues"]))) 321 MiscUtil.PrintInfo("Psi - Min: %s; Max: %s; Bin size: %s; Count: %s" % (DensityInfo["PsiValues"][0], DensityInfo["PsiValues"][-1], abs(DensityInfo["PsiValues"][1] - DensityInfo["PsiValues"][0]), len(DensityInfo["PsiValues"]))) 322 323 return DensityInfo 324 325 def CalculatePhiPsiAngles(): 326 """Calculate phi and psi angles for scatter plots.""" 327 328 Infile = OptionsInfo["Infile"] 329 MolName = OptionsInfo["InfileRoot"] 330 331 # Load molecule... 332 pymol.cmd.reinitialize() 333 pymol.cmd.load(Infile, MolName) 334 335 MiscUtil.PrintInfo("\nCalculating phi and psi torsion angles for input file %s..." % Infile) 336 337 # Initialize... 338 OptionsInfo["PlotTypesInfo"]["PhiAngles"] = {} 339 OptionsInfo["PlotTypesInfo"]["PsiAngles"] = {} 340 OptionsInfo["PlotTypesInfo"]["ResCount"] = {} 341 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 342 OptionsInfo["PlotTypesInfo"]["PhiAngles"][PlotType] = [] 343 OptionsInfo["PlotTypesInfo"]["PsiAngles"][PlotType] = [] 344 OptionsInfo["PlotTypesInfo"]["ResCount"][PlotType] = 0 345 346 Precision = OptionsInfo["Precision"] 347 348 TotalResCount = 0 349 # Go over specified chain IDs.. 350 for ChainID in OptionsInfo["SpecifiedChainsAndLigandsInfo"]["ChainIDs"]: 351 PhiPsiInfoList = [] 352 GeneralPhiPsiInfo, GlycinePhiPsiInfo, ProlinePhiPsiInfo, PreProlinePhiPsiInfo = PyMOLUtil.GetPhiPsiCategoriesResiduesInfo(MolName, ChainID) 353 PhiPsiInfoList.extend([GeneralPhiPsiInfo, GlycinePhiPsiInfo, ProlinePhiPsiInfo, PreProlinePhiPsiInfo]) 354 355 for Index, PlotType in enumerate(OptionsInfo["PlotTypesInfo"]["Types"]): 356 PhiPsiInfo = PhiPsiInfoList[Index] 357 ResCount = len(PhiPsiInfo["ResNums"]) 358 if not ResCount: 359 continue 360 361 TotalResCount += ResCount 362 OptionsInfo["PlotTypesInfo"]["ResCount"][PlotType] += ResCount 363 364 PhiAngles, PsiAngles = ProcessPsiInfo(PhiPsiInfo, Precision) 365 OptionsInfo["PlotTypesInfo"]["PhiAngles"][PlotType].extend(PhiAngles) 366 OptionsInfo["PlotTypesInfo"]["PsiAngles"][PlotType].extend(PsiAngles) 367 368 # Delete MolName object 369 pymol.cmd.delete(MolName) 370 371 MiscUtil.PrintInfo("\nTotal number of phi and psi angles: %d" % TotalResCount) 372 373 MiscUtil.PrintInfo("") 374 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 375 MiscUtil.PrintInfo("Number of \"%s\" phi and psi angles: %s" % (PlotType, OptionsInfo["PlotTypesInfo"]["ResCount"][PlotType])) 376 377 if not TotalResCount: 378 MiscUtil.PrintInfo("") 379 MiscUtil.PrintWarning("No valid phi and psi angles found in input file. Ramachandran plots will be generated without phi and psi scatter plots...") 380 381 def ProcessPsiInfo(PhiPsiInfo, Precision): 382 """Process phi and psi angels for scatter plots.""" 383 384 PhiAngles = [] 385 PsiAngles = [] 386 for ResNum in PhiPsiInfo["ResNums"]: 387 Phi = "%.*f" % (Precision, PhiPsiInfo["Phi"][ResNum]) 388 Psi = "%.*f" % (Precision, PhiPsiInfo["Psi"][ResNum]) 389 PhiAngles.append(float(Phi)) 390 PsiAngles.append(float(Psi)) 391 392 return PhiAngles, PsiAngles 393 394 def RetrieveInfileInfo(): 395 """Retrieve information for input file.""" 396 397 Infile = OptionsInfo["Infile"] 398 InfileRoot = OptionsInfo["InfileRoot"] 399 400 ChainsAndLigandsInfo = PyMOLUtil.GetChainsAndLigandsInfo(Infile, InfileRoot) 401 OptionsInfo["ChainsAndLigandsInfo"] = ChainsAndLigandsInfo 402 403 def ProcessChainIDs(): 404 """Process specified chain IDs for infile.""" 405 406 MiscUtil.PrintInfo("\nProcessing specified chain IDs for input file %s..." % OptionsInfo["Infile"]) 407 ChainsAndLigandsInfo = OptionsInfo["ChainsAndLigandsInfo"] 408 SpecifiedChainsAndLigandsInfo = PyMOLUtil.ProcessChainsAndLigandsOptionsInfo(ChainsAndLigandsInfo, "-c, --chainIDs", OptionsInfo["ChainIDs"], None, None) 409 410 OptionsInfo["SpecifiedChainsAndLigandsInfo"] = SpecifiedChainsAndLigandsInfo 411 412 MiscUtil.PrintInfo("Specified chain IDs: %s" % (", ".join(SpecifiedChainsAndLigandsInfo["ChainIDs"]))) 413 414 def SetupPlotsInfo(): 415 """Setup information for generating plots.""" 416 417 InitializePlotTypesInfo() 418 SetupPlotTypesOutfiles() 419 420 ProessContourLevelsAndColors() 421 422 def ProessContourLevelsAndColors(): 423 """Process specified contour levels and colors.""" 424 425 if re.match("^auto$", OptionsInfo["LevelsAndColors"], re.I): 426 return 427 428 # Setup canonical plot types for validation... 429 CanonicalPlotTypes = {} 430 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 431 CanonicalPlotTypes[PlotType.lower()] = PlotType 432 433 LevelsAndColors = re.sub(" ", "", OptionsInfo["LevelsAndColors"]) 434 if not len(LevelsAndColors): 435 MiscUtil.PrintError("The levels and colors specified using \"-l, --levelsAndColors\" option are empty.") 436 437 for TypeLevelsColorsWord in LevelsAndColors.split(";"): 438 if not len(TypeLevelsColorsWord): 439 MiscUtil.PrintError("The plot types, levels, and colors, \"%s\" specified using \"-l, --levelsAndColors\" option in, \"%s\", is empty." % (TypeLevelsColorsWord, LevelsAndColors)) 440 441 TypeLevelsColorsWords = TypeLevelsColorsWord.split(":") 442 if len(TypeLevelsColorsWords) !=2: 443 MiscUtil.PrintError("The format of plot type, levels, and colors specification, \"%s\", specified using \"-l, --levelsAndColors\" option, in \"%s\", is not valid: Supported format: <PlotType>: <Level>, <Color>, <Level>,..." % (TypeLevelsColorsWord, OptionsInfo["LevelsAndColors"])) 444 445 PlotType = TypeLevelsColorsWords[0] 446 if not len(PlotType): 447 MiscUtil.PrintError("The plot type, \"%s\" specified using \"-l, --levelsAndColors\" option in, \"%s\", is empty." % (PlotType, TypeLevelsColorsWord)) 448 CanonicalPlotType = PlotType.lower() 449 450 if not CanonicalPlotType in CanonicalPlotTypes: 451 MiscUtil.PrintError("The plot type, \"%s\" specified using \"-l, --levelsAndColors\" option in, \"%s\", is not valid. Supported valus: %s" % (PlotType, TypeLevelsColorsWord, ", ".join(OptionsInfo["PlotTypesInfo"]["Types"]))) 452 PlotType = CanonicalPlotTypes[CanonicalPlotType] 453 454 LevelsColorsWords = TypeLevelsColorsWords[1].split(",") 455 if not (len(LevelsColorsWords) % 2): 456 MiscUtil.PrintError("The format of levels and colors specifification, \"%s\", specified using \"-l, --levelsAndColors\" option in, \"%s\", is not valid. It must contain odd number of values. Supported format: <PlotType>: <Level>, <Color>, <Level>,..." % (", ".join(LevelsColorsWords), TypeLevelsColorsWord)) 457 458 # Retrieve levels and colors... 459 Levels = [] 460 Colors = [] 461 for Index, SpecWord in enumerate(LevelsColorsWords): 462 if not len(SpecWord): 463 MiscUtil.PrintError("The level or color, \"%s\" specified using \"-l, --levelsAndColors\" option in, \"%s\", is empty." % (SpecWord, TypeLevelsColorsWord)) 464 465 if Index % 2: 466 Colors.append(SpecWord) 467 continue 468 469 # Process level... 470 if not MiscUtil.IsFloat(SpecWord): 471 MiscUtil.PrintError("The level, \"%s\" specified using \"-l, --levelsAndColors\" option in, \"%s\", must be a number." % (SpecWord, TypeLevelsColorsWord)) 472 473 Level = float(SpecWord) 474 if len(Levels): 475 # The current level must be greater than all previous levels.. 476 for PreviousLevel in Levels: 477 if Level <= PreviousLevel: 478 MiscUtil.PrintError("The level, \"%s\" specified using \"-l, --levelsAndColors\" option in, \"%s\", must be greater than all previous levels." % (SpecWord, TypeLevelsColorsWord)) 479 480 Levels.append(Level) 481 482 OptionsInfo["PlotTypesInfo"]["Levels"][PlotType] = Levels 483 OptionsInfo["PlotTypesInfo"]["Colors"][PlotType] = Colors 484 485 def InitializePlotTypesInfo(): 486 """Initialize information for generating plots.""" 487 488 PlotTypesInfo = {} 489 PlotTypesInfo["Types"] = [] 490 PlotTypesInfo["PhiPsiDensityFiles"] = {} 491 PlotTypesInfo["PhiPsiDensityInfo"] = {} 492 PlotTypesInfo["PhiPsiContourInfo"] = {} 493 494 PlotTypesInfo["Titles"] = {} 495 PlotTypesInfo["DrawXLabel"] = {} 496 PlotTypesInfo["DrawYLabel"] = {} 497 498 PlotTypesInfo["Limits"] = {} 499 PlotTypesInfo["MajorTickPositions"] = {} 500 PlotTypesInfo["MajorTickLabels"] = {} 501 PlotTypesInfo["MinorTickPositions"] = {} 502 503 PlotTypesInfo["Levels"] = {} 504 PlotTypesInfo["Colors"] = {} 505 PlotTypesInfo["Outfiles"] = {} 506 PlotTypesInfo["PhiAngles"] = {} 507 PlotTypesInfo["PsiAngles"] = {} 508 509 MayaChemToolsDataDir = MiscUtil.GetMayaChemToolsLibDataPath() 510 511 # Setup contour colors for supported default schemes... 512 ContourColorSchemes = {} 513 ContourColorSchemes["General"] = {"MuttedColorShades1": ["#FFFFFF", "#EBF1DE", "#C3D69B"], 514 "MuttedColorShades2": ["#FFFFFF", "#EBF1DE", "#D7E4BD"], 515 "BrightColorShades": ["#FFFFFF", "#B3E8FF", "#7FD9FF"]} 516 ContourColorSchemes["Glycine"] = {"MuttedColorShades1": ["#FFFFFF", "#FDEADA", "#FAC090"], 517 "MuttedColorShades2": ["#FFFFFF", "#FDEADA", "#FCD5B5"], 518 "BrightColorShades": ["#FFFFFF", "#FFE8C5", "#FFCC7F"]} 519 ContourColorSchemes["Proline"] = {"MuttedColorShades1": ["#FFFFFF", "#E6E0EC", "#B3A2C7"], 520 "MuttedColorShades2": ["#FFFFFF", "#E6E0EC", "#CCC1DA"], 521 "BrightColorShades": ["#FFFFFF", "#D0FFC5", "#7FFF8C"]} 522 ContourColorSchemes["PreProline"] = {"MuttedColorShades1": ["#FFFFFF", "#DCE6F2", "#95B3D7"], 523 "MuttedColorShades2": ["#FFFFFF", "#DCE6F2", "#B9CDE5"], 524 "BrightColorShades": ["#FFFFFF", "#B3E8FF", "#7FD9FF"]} 525 526 if re.match("^MuttedColorShades1$", OptionsInfo["LevelsAndColorsScheme"], re.I): 527 DefaultColorScheme = "MuttedColorShades1" 528 elif re.match("^MuttedColorShades2$", OptionsInfo["LevelsAndColorsScheme"], re.I): 529 DefaultColorScheme = "MuttedColorShades2" 530 elif re.match("^BrightColorShades$", OptionsInfo["LevelsAndColorsScheme"], re.I): 531 DefaultColorScheme = "BrightColorShades" 532 else: 533 MiscUtil.PrintError("The color scheme, %s, specified using \"--levelsAndColorsScheme\" option is not supported." % (OptionsInfo["LevelsAndColorsScheme"])) 534 535 for Type in ["General", "Glycine", "Proline", "PreProline"]: 536 PlotTypesInfo["Types"].append(Type) 537 538 # Setup phi and psi density file... 539 DensityFile = os.path.join(MayaChemToolsDataDir, "PhiPsiDensity%s.csv" % (Type)) 540 if not os.path.exists(DensityFile): 541 MiscUtil.PrintError("The phi and psi density file file, %s, doesn't exist. This is required for generating contour plots.\n" % (DensityFile)) 542 PlotTypesInfo["PhiPsiDensityFiles"][Type] = DensityFile 543 544 # Setup plot title... 545 Title = Type 546 if re.match("^PreProline$", Type, re.I): 547 Title = "pre-Proline" 548 PlotTypesInfo["Titles"][Type] = Title 549 550 # Setup flags for drawing axis labels... 551 DrawXLabel, DrawYLabel = [True] * 2 552 if not OptionsInfo["MultipleOutFiles"]: 553 # Turn off XLabel for plots in first row... 554 DrawXLabel = False if re.match("^(General|Glycine)$", Type, re.I) else True 555 556 # Turn off YLabel for plots in second column... 557 DrawYLabel = False if re.match("^(Glycine|PreProline)$", Type, re.I) else True 558 PlotTypesInfo["DrawXLabel"][Type] = DrawXLabel 559 PlotTypesInfo["DrawYLabel"][Type] = DrawYLabel 560 561 # Setup limits... 562 (MinLimit, MaxLimit) = [-180, 180] 563 PlotTypesInfo["Limits"][Type] = [MinLimit, MaxLimit] 564 565 # Setup major tick labels and positions... 566 MajorTickPositions = list(range(MinLimit, MaxLimit, OptionsInfo["TicksMajorInterval"])) 567 MajorTickPositions.append(MaxLimit) 568 MajorTickLabels = ["%s" % Position for Position in MajorTickPositions] 569 PlotTypesInfo["MajorTickPositions"][Type] = MajorTickPositions 570 PlotTypesInfo["MajorTickLabels"][Type] = MajorTickLabels 571 572 # Setup minor tick positions without any labels... 573 MinorTickPositions = list(range(MinLimit, MaxLimit, OptionsInfo["TicksMinorInterval"])) 574 MinorTickPositions.append(MaxLimit) 575 PlotTypesInfo["MinorTickPositions"][Type] = MinorTickPositions 576 577 # Setup contour levels and colors... 578 Levels = [] 579 Colors = [] 580 if re.match("^General$", Type, re.I): 581 Levels = [0.0, 0.0005, 0.02, 1.0] 582 Colors = ContourColorSchemes[Type][DefaultColorScheme] 583 elif re.match("^Glycine$", Type, re.I): 584 Levels = [0.0, 0.002, 0.02, 1.0] 585 Colors = ContourColorSchemes[Type][DefaultColorScheme] 586 elif re.match("^Proline$", Type, re.I): 587 Levels = [0.0, 0.002, 0.02, 1.0] 588 Colors = ContourColorSchemes[Type][DefaultColorScheme] 589 elif re.match("^PreProline$", Type, re.I): 590 Levels = [0.0, 0.002, 0.02, 1.0] 591 Colors = ContourColorSchemes[Type][DefaultColorScheme] 592 593 PlotTypesInfo["Levels"][Type] = Levels 594 PlotTypesInfo["Colors"][Type] = Colors 595 596 OptionsInfo["PlotTypesInfo"] = PlotTypesInfo 597 598 def SetupPlotTypesOutfiles(): 599 """Setup output file names for plot types.""" 600 601 OptionsInfo["OutfilesList"] = [] 602 OptionsInfo["OutfilesList"].append(OptionsInfo["Outfile"]) 603 604 OptionsInfo["PlotTypesInfo"]["Outfiles"] = {} 605 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 606 OptionsInfo["PlotTypesInfo"]["Outfiles"][PlotType] = None 607 608 if not OptionsInfo["MultipleOutFiles"]: 609 return 610 611 FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"]) 612 OutfileRoot = FileName 613 OutfileExt = FileExt 614 615 for PlotType in OptionsInfo["PlotTypesInfo"]["Types"]: 616 PlotOutfile = "%s_%s.%s" % (OutfileRoot, PlotType, OutfileExt) 617 if os.path.exists(PlotOutfile): 618 if not OptionsInfo["Overwrite"]: 619 MiscUtil.PrintError("The plot output file, %s, already exist. Use option \"--ov\" or \"--overwrite\" and try again.\n" % (PlotOutfile)) 620 621 OptionsInfo["PlotTypesInfo"]["Outfiles"][PlotType] = PlotOutfile 622 OptionsInfo["OutfilesList"].append(PlotOutfile) 623 624 def ProcessOptions(): 625 """Process and validate command line arguments and options.""" 626 627 MiscUtil.PrintInfo("Processing options...") 628 629 # Validate options... 630 ValidateOptions() 631 632 OptionsInfo["OutMode"] = Options["--outMode"] 633 OptionsInfo["MultipleOutFiles"] = True if re.match("^MultipleFiles$", OptionsInfo["OutMode"], re.I) else False 634 MultipleOutFiles = OptionsInfo["MultipleOutFiles"] 635 636 OptionsInfo["FigDPI"] = int(Options["--figDPI"]) 637 638 FigSize = Options["--figSize"] 639 Width = 6.4 640 Height = 4.8 if MultipleOutFiles else 6.4 641 642 if not re.match("^auto$", FigSize, re.I): 643 FigSizeWords = FigSize.split(",") 644 Width = float(FigSizeWords[0]) 645 Height = float(FigSizeWords[1]) 646 OptionsInfo["FigSize"] = FigSize 647 OptionsInfo["FigWidth"] = Width 648 OptionsInfo["FigHeight"] = Height 649 650 OptionsInfo["FontFamily"] = Options["--fontFamily"] 651 OptionsInfo["FontAxesSize"] = Options["--fontAxesSize"] 652 OptionsInfo["FontAxesWeight"] = Options["--fontAxesWeight"] 653 OptionsInfo["FontTicksSize"] = Options["--fontTicksSize"] 654 OptionsInfo["FontTicksWeight"] = Options["--fontTicksWeight"] 655 OptionsInfo["FontTitleSize"] = Options["--fontTitleSize"] 656 OptionsInfo["FontTitleWeight"] = Options["--fontTitleWeight"] 657 658 OptionsInfo["Greek"] = True if re.match("^Yes$", Options["--greek"], re.I) else False 659 660 OptionsInfo["Grid"] = True if re.match("^Yes$", Options["--grid"], re.I) else False 661 OptionsInfo["GridLineColor"] = Options["--gridLineColor"] 662 OptionsInfo["GridLineStyle"] = Options["--gridLineStyle"] 663 OptionsInfo["GridLineWidth"] = float(Options["--gridLineWidth"]) 664 665 OptionsInfo["Infile"] = Options["--infile"] 666 FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Infile"]) 667 OptionsInfo["InfileRoot"] = FileName 668 669 OptionsInfo["LevelsAndColorsScheme"] = Options["--levelsAndColorsScheme"] 670 671 OptionsInfo["Outfile"] = Options["--outfile"] 672 FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"]) 673 OptionsInfo["OutfileRoot"] = FileName 674 675 OptionsInfo["Overwrite"] = Options["--overwrite"] 676 OptionsInfo["Precision"] = int(Options["--precision"]) 677 678 OptionsInfo["ScatterMarkerColor"] = Options["--scatterMarkerColor"] 679 OptionsInfo["ScatterMarkerSize"] = float(Options["--scatterMarkerSize"]) 680 OptionsInfo["ScatterMarkerStyle"] = Options["--scatterMarkerStyle"] 681 682 TicksMajorInterval = 90 if MultipleOutFiles else 180 683 if not re.match("^auto$", Options["--ticksMajorInterval"], re.I): 684 TicksMajorInterval = int(Options["--ticksMajorInterval"]) 685 OptionsInfo["TicksMajorInterval"] = TicksMajorInterval 686 687 OptionsInfo["TicksMinor"] = True if re.match("^Yes$", Options["--ticksMinor"], re.I) else False 688 TicksMinorInterval = 10 if MultipleOutFiles else 45 689 if not re.match("^auto$", Options["--ticksMinorInterval"], re.I): 690 TicksMinorInterval = int(Options["--ticksMinorInterval"]) 691 OptionsInfo["TicksMinorInterval"] = TicksMinorInterval 692 693 RetrieveInfileInfo() 694 OptionsInfo["ChainIDs"] = Options["--chainIDs"] 695 696 ProcessChainIDs() 697 698 OptionsInfo["LevelsAndColors"] = Options["--levelsAndColors"] 699 SetupPlotsInfo() 700 701 def RetrieveOptions(): 702 """Retrieve command line arguments and options.""" 703 704 # Get options... 705 global Options 706 Options = docopt(_docoptUsage_) 707 708 # Set current working directory to the specified directory... 709 WorkingDir = Options["--workingdir"] 710 if WorkingDir: 711 os.chdir(WorkingDir) 712 713 # Handle examples option... 714 if "--examples" in Options and Options["--examples"]: 715 MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_)) 716 sys.exit(0) 717 718 def ValidateOptions(): 719 """Validate option values.""" 720 721 MiscUtil.ValidateOptionIntegerValue("--figDPI", Options["--figDPI"], {">": 0}) 722 if not re.match("^auto$", Options["--figSize"], re.I): 723 MiscUtil.ValidateOptionNumberValues("--figSize", Options["--figSize"], 2, ",", "float", {">": 0}) 724 725 MiscUtil.ValidateOptionFilePath("-i, --infile", Options["--infile"]) 726 MiscUtil.ValidateOptionFileExt("-i, --infile", Options["--infile"], "pdb cif") 727 728 MiscUtil.ValidateOptionTextValue("-g, --greek", Options["--greek"], "yes no") 729 730 MiscUtil.ValidateOptionTextValue("--grid", Options["--grid"], "yes no") 731 MiscUtil.ValidateOptionFloatValue("--gridLineWidth", Options["--gridLineWidth"], {">": 0}) 732 733 MiscUtil.ValidateOptionTextValue("--levelsAndColorsScheme", Options["--levelsAndColorsScheme"], "MuttedColorShades1 MuttedColorShades2 BrightColorShades") 734 735 MiscUtil.ValidateOptionsOutputFileOverwrite("-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"]) 736 737 MiscUtil.ValidateOptionTextValue("--outMode", Options["--outMode"], "SingleFile MultipleFiles") 738 MiscUtil.ValidateOptionIntegerValue("-p, --precision", Options["--precision"], {">": 0}) 739 740 MiscUtil.ValidateOptionFloatValue("--scatterMarkerSize", Options["--scatterMarkerSize"], {">": 0}) 741 742 if not re.match("^auto$", Options["--ticksMajorInterval"], re.I): 743 MiscUtil.ValidateOptionIntegerValue("--ticksMajorInterval", Options["--ticksMajorInterval"], {">": 0, "<": 360}) 744 745 MiscUtil.ValidateOptionTextValue("--ticksMinor", Options["--ticksMinor"], "yes no") 746 if not re.match("^auto$", Options["--ticksMinorInterval"], re.I): 747 MiscUtil.ValidateOptionIntegerValue("--ticksMinorInterval", Options["--ticksMinorInterval"], {">": 0, "<": 360}) 748 749 # Setup a usage string for docopt... 750 _docoptUsage_ = """ 751 PyMOLGenerateRamachandranPlots.py - Generate Ramachandran plots 752 753 Usage: 754 PyMOLGenerateRamachandranPlots.py [--chainIDs <First, All or ID1,ID2...>] 755 [--figDPI <number>] [--figSize <width, height>] [--fontFamily <text>] 756 [--fontAxesSize <number or text>] [--fontAxesWeight <number or text>] 757 [--fontTicksSize <number or text>] [--fontTicksWeight <number or text>] 758 [--fontTitleSize <number or text>] [--fontTitleWeight <number or text>] [--greek <yes or no>] 759 [--grid <yes or no>] [--gridLineColor <text>] [--gridLineStyle <text>] [--gridLineWidth <number>] 760 [--levelsAndColors <PlotType:Level,color,Level,...;...>] [--levelsAndColorsScheme <text>] 761 [--outMode <SingleFile or MultipleFiles>] [--overwrite] [--precision <number>] 762 [--scatterMarkerColor <text>] [--scatterMarkerSize <number>] [--scatterMarkerStyle <text>] 763 [--ticksMajorInterval <number>] [--ticksMinor <yes or no>] [--ticksMinorInterval <number>] 764 [-w <dir>] -i <infile> -o <outfile> 765 PyMOLGenerateRamachandranPlots.py -h | --help | -e | --examples 766 767 Description: 768 Generate Ramachandran plots for amino acid residues present in macromolecules. 769 770 The Ramachandran plots are generated by plotting phi and psi backbone angles 771 corresponding to the following four categories of amino acids: 772 773 General: All residues except glycine, proline, or pre-proline 774 Glycine: Only glycine residues 775 Proline: Only proline residues 776 PreProline: Only residues before proline not including glycine or 777 proline 778 779 In addition to the scatter plots for phi and psi angles, the filled contours 780 are generated for the density of phi and psi angles [ Ref 144 ] for the 781 Ramachandran plots. The contours are generated for "favored" and "allowed" 782 regions. The phi and psi density is retrieved from the following density files 783 available in MAYACHEMTOOLS/lib/data/ directory: 784 785 General: PhiPsiDensityGeneral.csv 786 Glycine: PhiPsiDensityGlycine.csv 787 Proline: PhiPsiDensityProline.csv 788 PreProline: PhiPsiDensityPreProline.csv 789 790 The supported input file format are: PDB (.pdb), mmCIF (.cif) 791 792 The output image file can be saved in any format supported by Python 793 module Matplotlib. The image format is automatically detected from the 794 output file extension. 795 796 Some of the most common output image file formats are: EPS (.eps), PDF (.pdf), 797 PNG (.png), PS (.ps), SVG (.svg). 798 799 Options: 800 -c, --chainIDs <First, All or ID1,ID2...> [default: All] 801 List of chain IDs to use for calculating phi and psi angles for residues 802 in chains. Possible values: First, All, or a comma delimited list of chain 803 IDs. The default is to use all chain IDs in input file. 804 -e, --examples 805 Print examples. 806 --figDPI <number> [default: 300] 807 Figure resolution in dots per inches. The DPI value must be supported 808 by Matplotlib during generation of an image of a specific format. No 809 validation is performed. 810 --figSize <width, height> [default: auto] 811 Figure dimensions in inches. The default values are dependent on the 812 the value of '--outMode' option as shown below: 813 814 SingleFile: 6.4, 6.4 815 MultipleFiles: 6.4, 4.8 816 817 --fontFamily <text> [default: auto] 818 Font family to use for title, axes labels, and tick marks. It must be a 819 valid Matplotlib value. The default value corresponds to the value 820 plt.rcParams["font.family"] in your environment. For example: serif, 821 sans-serif, cursive, etc. 822 --fontAxesSize <number or text> [default: 10] 823 Font size for labels on axes. It must be valid Matplotlib font size. For 824 example: size in points, xx-small, x-small, small, medium, etc. 825 --fontAxesWeight <number or text> [default: regular] 826 Font weight for labels on axes. It must be valid Matplotlib value. For 827 example: a numeric value in range 0-1000, ultralight, light, normal, 828 regular, book, medium, etc. 829 --fontTicksSize <number or text> [default: 8] 830 Font size for tick labels. It must be a valid Matplotlib font size. For 831 example: size in points, xx-small, x-small, small, medium, etc. 832 --fontTicksWeight <number or text> [default: regular] 833 Font weight for tick labels. It must be valid Matplotlib value. For 834 example: a numeric value in range 0-1000, ultralight, light, 835 normal, regular, book, medium, etc. 836 --fontTitleSize <number or text> [default: 10] 837 Font size for title. It must be a valid Matplotlib font size. For example: 838 size in points, xx-small, x-small, small, medium, etc. 839 --fontTitleWeight <number or text> [default: bold] 840 Font weight for title. It must be a valid Matplotlib value. For example: a 841 numeric value in range 0-1000, ultralight, light, normal, regular, book, 842 medium, etc. 843 -g, --greek <yes or no> [default: yes] 844 Show phi and psi labels as greek characters. 845 --grid <yes or no> [default: yes] 846 Display grid lines at major tick marks. 847 --gridLineColor <text> [default: #b0b0b0] 848 Grid line color. It must be a valid Matplotlib value. The default color 849 is light gray. 850 --gridLineStyle <text> [default: dotted] 851 Grid line style. It must be a valid Matplotlib value. For example: 852 '-' or 'solid', --' or 'dashed', '-.' or 'dashdot', ':' or 'dotted' etc. 853 --gridLineWidth <number> [default: 0.8] 854 Grid line width. It must be a valid Matplotlib value. 855 -h, --help 856 Print this help message. 857 -i, --infile <infile> 858 Input file name. 859 -l, --levelsAndColors <PlotType:Level,color,Level,...;...> [default: auto] 860 Semicolon delimited list of contour levels and colors for four types 861 of Ramachandran plots. 862 863 Three default contour level and color scheme may be specified by 864 '--levelsAndColorsScheme' option. By default, the 'MuttedColorShades1' 865 scheme is used. The default contour levels correspond to 'favored' and 866 'allowed' regions [ Ref 144 ] for phi and psi angles. 867 868 The colors are used to fill spaces between contour levels. The values 869 for contour levels must be ascending order. The number of colors 870 must be one less than the number contour levels. 871 872 The format of contour level and color specification is as follows: 873 874 PlotType:Level,Color,Level,...;PlotType:Level,Color,Level,... 875 876 The valid values for plot type are: 877 878 General, Glycine, Proline, or PreProline 879 880 The contour level must be a number. The color value must be a valid color 881 name or a hexadecimal color string supported by Matplotlib. No validation 882 is performed. 883 884 For example: 885 886 General: 0.0, #FFFFFF, 0.0005, #EBF1DE, 0.02, #C3D69B, 1.0 887 888 --levelsAndColorsScheme <text> [default: MuttedColorShades1] 889 Default contour levels and colors scheme. Possible values: 890 MuttedColorShades1, MuttedColorShades2, or BrightColorShades. 891 892 This option is only used during 'auto' value of '--levelsAndColors' option. 893 The default contour levels correspond to 'favored' and 'allowed' regions 894 [ Ref 144 ] for phi and psi angles. 895 896 The default contour and color values for different default schemes are 897 shown below: 898 899 MuttedColorShades1: 900 901 General: 0.0, #FFFFFF, 0.0005, #EBF1DE, 0.02, #C3D69B, 1.0 902 Glycine: 0.0, #FFFFFF, 0.002, #7FD9FF, 0.02, #FAC090, 1.0 903 Proline: 0.0, #FFFFFF, 0.002, #E6E0EC, 0.02, #B3A2C7, 1.0 904 PreProline: 0.0, #FFFFFF, 0.002, #DCE6F2, 0.02, #95B3D7, 1.0 905 906 MuttedColorShades2: 907 908 General: 0.0, #FFFFFF, 0.0005, #EBF1DE, 0.02, #D7E4BD, 1.0 909 Glycine: 0.0, #FFFFFF, 0.002, #FDEADA, 0.02, #FCD5B5, 1.0 910 Proline: 0.0, #FFFFFF, 0.002, #E6E0EC, 0.02, #CCC1DA, 1.0 911 PreProline: 0.0, #FFFFFF, 0.002, #DCE6F2, 0.02, #B9CDE5, 1.0 912 913 BrightColorShades: [ Ref 145 ] 914 915 General: 0.0, #FFFFFF, 0.0005, #B3E8FF, 0.02, #7FD9FF, 1.0 916 Glycine: 0.0, #FFFFFF, 0.002, #FFE8C5, 0.02, #FFCC7F, 1.0 917 Proline: 0.0, #FFFFFF, 0.002, #D0FFC5, 0.02, #7FFF8C, 1.0 918 PreProline: 0.0, #FFFFFF, 0.002, #B3E8FF, 0.02, #7FD9FF, 1.0 919 920 -o, --outfile <outfile> 921 Output image file name. 922 923 A set of output files is optionally generated for 'MultipleFiles' value of 924 '--outMode' option. The names of these output files are automatically 925 generated from the the name of the specified output file as shown 926 below: 927 928 General: <OutfileRoot>_General.<OutfileExt> 929 Glycine: <OutfileRoot>_Glycine.<OutfileExt> 930 Proline: <OutfileRoot>_Proline.<OutfileExt> 931 PreProline: <OutfileRoot>_PreProline.<OutfileExt> 932 933 --outMode <Single or Multiple> [default: SingleFile] 934 A single output file containing all four Ramachandran plots or multiple 935 output files corresponding to different types of Ramachandran plots. 936 937 The phi and psi angles are categorized into the following groups 938 corresponding to four types of Ramachandran plots: 939 940 General: All residues except glycine, proline, or pre-proline 941 Glycine: Only glycine residues 942 Proline: Only proline residues 943 PreProline: Only residues before proline not including glycine or 944 proline 945 946 --overwrite 947 Overwrite existing files. 948 -p, --precision <number> [default: 2] 949 Floating point precision for plotting the calculated phi and psi angles. 950 --scatterMarkerColor <text> [default: #1f77b4] 951 Scatter marker color for plotting to phi and psi angles. It must be a 952 valid Matplotlib value. The default color is dark blue. 953 --scatterMarkerSize <number> [default: 1.0] 954 Scatter marker size for piloting phi and psi angles. It must be a valid 955 Matplotlib value. 956 --scatterMarkerStyle <text> [default: .] 957 Scatter marker style for piloting phi and psi angles. It must be a valid 958 Matplotlib value. For example: '.' (point), ',' (pixel), 'o' (circle), etc. 959 --ticksMajorInterval <number> [default: auto] 960 Display major marks on axes at intervals specified in degrees for phi and 961 psi angles. The default value is dependent on the the value of '--outMode' 962 option: SingleFile: 180; MultipleFiles: 90 963 964 The grid lines are drawn at the locations of major tick marks. 965 --ticksMinor <yes or no> [default: yes] 966 Display minor tick marks. The major tick mark are always displayed. 967 --ticksMinorInterval <number> [default: auto] 968 Display minor marks on axes at intervals specified in degrees for phi and 969 psi angles. The default value is dependent on the the value of '--outMode' 970 option: SingleFile: 45; MultipleFiles: 10 971 -w, --workingdir <dir> 972 Location of working directory which defaults to the current directory. 973 974 Examples: 975 To generate Ramachandran plot for all residues across all chains in input 976 file and write out a single SVG file containing all four types of plots, type: 977 978 % PyMOLGenerateRamachandranPlots.py -i Sample3.pdb -o Sample3Out.svg 979 980 To generate Ramachandran plot for all residues across all chains in input 981 file and write out four SVG files corresponding to four types of plots, type: 982 983 % PyMOLGenerateRamachandranPlots.py --outMode MultipleFiles 984 -i Sample3.pdb -o Sample3Out.svg 985 986 To generate Ramachandran plot for all residues in a specific chain in input 987 file and write out a single PDF file containing all four types of plots, type: 988 989 % PyMOLGenerateRamachandranPlots.py -c E -i Sample3.pdb 990 -o Sample3Out.pdf 991 992 To generate Ramachandran plot for all residues across all chains in input 993 file using specific options and write out four PNG files containing all four 994 types of plots, type: 995 996 % PyMOLGenerateRamachandranPlots.py --outMode MultipleFiles 997 --figSize "6,4" --figDPI 600 --fontTitleSize 10 --fontTitleWeight 998 normal --greek no --grid no --levelsAndColors 999 "General: 0.0, #FFFFFF, 0.0005, #B3E8FF, 0.02, #7FD9FF, 1.0" 1000 -i Sample3.pdb -o Sample3Out.png 1001 1002 Author: 1003 Manish Sud(msud@san.rr.com) 1004 1005 See also: 1006 DownloadPDBFiles.pl, PyMOLCalculatePhiPsiAngles.py, PyMOLCalculateRMSD.py, 1007 PyMOLCalculateProperties.py 1008 1009 Copyright: 1010 Copyright (C) 2025 Manish Sud. All rights reserved. 1011 1012 The functionality available in this script is implemented using PyMOL, a 1013 molecular visualization system on an open source foundation originally 1014 developed by Warren DeLano. 1015 1016 This file is part of MayaChemTools. 1017 1018 MayaChemTools is free software; you can redistribute it and/or modify it under 1019 the terms of the GNU Lesser General Public License as published by the Free 1020 Software Foundation; either version 3 of the License, or (at your option) any 1021 later version. 1022 1023 """ 1024 1025 if __name__ == "__main__": 1026 main()