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