1 #!/bin/env python
2 #
3 # File: PyMOLVisualizeCryoEMDensity.py
4 # Author: Manish Sud <msud@san.rr.com>
5 #
6 # Copyright (C) 2025 Manish Sud. All rights reserved.
7 #
8 # The functionality available in this script is implemented using PyMOL, a
9 # molecular visualization system on an open source foundation originally
10 # developed by Warren DeLano.
11 #
12 # This file is part of MayaChemTools.
13 #
14 # MayaChemTools is free software; you can redistribute it and/or modify it under
15 # the terms of the GNU Lesser General Public License as published by the Free
16 # Software Foundation; either version 3 of the License, or (at your option) any
17 # later version.
18 #
19 # MayaChemTools is distributed in the hope that it will be useful, but without
20 # any warranty; without even the implied warranty of merchantability of fitness
21 # for a particular purpose. See the GNU Lesser General Public License for more
22 # details.
23 #
24 # You should have received a copy of the GNU Lesser General Public License
25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
27 # Boston, MA, 02111-1307, USA.
28 #
29
30 from __future__ import print_function
31
32 import os
33 import sys
34 import time
35 import re
36 import xml.etree.ElementTree as ElementTree
37
38 # PyMOL imports...
39 try:
40 import pymol
41
42 # Finish launching PyMOL in a command line mode for batch processing (-c)
43 # along with the following options: disable loading of pymolrc and plugins (-k);
44 # suppress start up messages (-q)
45 pymol.finish_launching(["pymol", "-ckq"])
46 except ImportError as ErrMsg:
47 sys.stderr.write("\nFailed to import PyMOL module/package: %s\n" % ErrMsg)
48 sys.stderr.write("Check/update your PyMOL environment and try again.\n\n")
49 sys.exit(1)
50
51 # MayaChemTools imports...
52 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
53 try:
54 from docopt import docopt
55 import MiscUtil
56 import PyMOLUtil
57 except ImportError as ErrMsg:
58 sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
59 sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
60 sys.exit(1)
61
62 ScriptName = os.path.basename(sys.argv[0])
63 Options = {}
64 OptionsInfo = {}
65
66
67 def main():
68 """Start execution of the script."""
69
70 MiscUtil.PrintInfo(
71 "\n%s (PyMOL v%s; MayaChemTools v%s; %s): Starting...\n"
72 % (ScriptName, pymol.cmd.get_version()[0], MiscUtil.GetMayaChemToolsVersion(), time.asctime())
73 )
74
75 (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
76
77 # Retrieve command line arguments and options...
78 RetrieveOptions()
79
80 # Process and validate command line arguments and options...
81 ProcessOptions()
82
83 # Perform actions required by the script...
84 GenerateCryoEMDensityVisualization()
85
86 MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
87 MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
88
89
90 def GenerateCryoEMDensityVisualization():
91 """Generate cryo-EM density visualization."""
92
93 Outfile = OptionsInfo["PMLOutfile"]
94 OutFH = open(Outfile, "w")
95 if OutFH is None:
96 MiscUtil.PrintError("Failed to open output fie %s " % Outfile)
97
98 MiscUtil.PrintInfo("\nGenerating file %s..." % Outfile)
99
100 # Setup header...
101 WritePMLHeader(OutFH, ScriptName)
102 WritePyMOLParameters(OutFH)
103
104 # Load reffile for alignment..
105 if OptionsInfo["Align"]:
106 WriteAlignReference(OutFH)
107
108 # Setup view for each input file...
109 FirstComplex = True
110 FirstComplexFirstChainName = None
111 for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
112 # Setup PyMOL object names...
113 PyMOLObjectNames = SetupPyMOLObjectNames(FileIndex)
114
115 # Setup complex view...
116 WriteComplexView(OutFH, FileIndex, PyMOLObjectNames, FirstComplex)
117
118 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
119 FirstChain = True
120 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
121 if FirstComplex and FirstChain:
122 FirstComplexFirstChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
123
124 WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID)
125
126 # Setup ligand views...
127 FirstLigand = True
128 for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
129 WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID)
130
131 # Set up ligand level group...
132 Enable, Action = [False, "close"]
133 if FirstLigand:
134 FirstLigand = False
135 Enable, Action = [True, "open"]
136 GenerateAndWritePMLForGroup(
137 OutFH,
138 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"],
139 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"],
140 Enable,
141 Action,
142 )
143
144 # Setup Chain level group...
145 Enable, Action = [False, "close"]
146 if FirstChain:
147 FirstChain = False
148 Enable, Action = [True, "open"]
149 GenerateAndWritePMLForGroup(
150 OutFH,
151 PyMOLObjectNames["Chains"][ChainID]["ChainGroup"],
152 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"],
153 Enable,
154 Action,
155 )
156
157 # Set up complex level group...
158 Enable, Action = [False, "close"]
159 if FirstComplex:
160 FirstComplex = False
161 Enable, Action = [True, "open"]
162 GenerateAndWritePMLForGroup(
163 OutFH, PyMOLObjectNames["PDBGroup"], PyMOLObjectNames["PDBGroupMembers"], Enable, Action
164 )
165
166 # Delete empty PyMOL objects...
167 DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames)
168
169 if OptionsInfo["Align"]:
170 DeleteAlignReference(OutFH)
171
172 if FirstComplexFirstChainName is not None:
173 OutFH.write("""\ncmd.orient("%s", animate = -1)\n""" % FirstComplexFirstChainName)
174 else:
175 OutFH.write("""\ncmd.orient("visible", animate = -1)\n""")
176
177 OutFH.close()
178
179 # Generate PSE file as needed...
180 if OptionsInfo["PSEOut"]:
181 GeneratePyMOLSessionFile()
182
183
184 def WritePMLHeader(OutFH, ScriptName):
185 """Write out PML setting up complex view."""
186
187 HeaderInfo = PyMOLUtil.SetupPMLHeaderInfo(ScriptName)
188 OutFH.write("%s\n" % HeaderInfo)
189
190
191 def WritePyMOLParameters(OutFH):
192 """Write out PyMOL global parameters."""
193
194 PMLCmds = []
195 PMLCmds.append("""cmd.set("mesh_width", %.2f)""" % (OptionsInfo["MeshWidth"]))
196 PMLCmds.append("""cmd.set("transparency", %.2f, "", 0)""" % (OptionsInfo["SurfaceTransparency"]))
197 PMLCmds.append("""cmd.set("label_font_id", %s)""" % (OptionsInfo["LabelFontID"]))
198
199 if OptionsInfo["VolumeColorRampCreate"]:
200 ColorRampName = OptionsInfo["VolumeColorRampName"]
201 ContourLevel = OptionsInfo["VolumeColorRampContourLevel"]
202 LowerContourLevel = ContourLevel - 0.3
203 UpperContourLevel = ContourLevel + 0.3
204 PMLCmds.append(
205 """cmd.volume_ramp_new("%s", "%.2f blue 0.00 %.2f cyan 0.20 %.2f blue 0.00")"""
206 % (ColorRampName, LowerContourLevel, ContourLevel, UpperContourLevel)
207 )
208
209 PML = "\n".join(PMLCmds)
210
211 OutFH.write("""\n""\n"Setting up PyMOL gobal parameters..."\n""\n""")
212 OutFH.write("%s\n" % PML)
213
214
215 def WriteAlignReference(OutFH):
216 """Setup object for alignment reference."""
217
218 RefFileInfo = OptionsInfo["RefFileInfo"]
219 RefFile = RefFileInfo["RefFileName"]
220 RefName = RefFileInfo["PyMOLObjectName"]
221
222 PMLCmds = []
223 PMLCmds.append("""cmd.load("%s", "%s")""" % (RefFile, RefName))
224 PMLCmds.append("""cmd.hide("everything", "%s")""" % (RefName))
225 PMLCmds.append("""cmd.disable("%s")""" % (RefName))
226 PML = "\n".join(PMLCmds)
227
228 OutFH.write("""\n""\n"Loading %s and setting up view for align reference..."\n""\n""" % RefFile)
229 OutFH.write("%s\n" % PML)
230
231
232 def WriteAlignComplex(OutFH, FileIndex, PyMOLObjectNames):
233 """Setup alignment of complex to reference."""
234
235 RefFileInfo = OptionsInfo["RefFileInfo"]
236 RefName = RefFileInfo["PyMOLObjectName"]
237
238 ComplexName = PyMOLObjectNames["Complex"]
239
240 if re.match("^FirstChain$", OptionsInfo["AlignMode"], re.I):
241 RefFirstChainID = RefFileInfo["ChainsAndLigandsInfo"]["ChainIDs"][0]
242 RefAlignSelection = "%s and chain %s" % (RefName, RefFirstChainID)
243
244 ComplexFirstChainID = RetrieveFirstChainID(FileIndex)
245 ComplexAlignSelection = "%s and chain %s" % (ComplexName, ComplexFirstChainID)
246 else:
247 RefAlignSelection = RefName
248 ComplexAlignSelection = ComplexName
249
250 PML = PyMOLUtil.SetupPMLForAlignment(OptionsInfo["AlignMethod"], RefAlignSelection, ComplexAlignSelection)
251 OutFH.write("""\n""\n"Aligning %s against reference %s ..."\n""\n""" % (ComplexAlignSelection, RefAlignSelection))
252 OutFH.write("%s\n" % PML)
253
254
255 def DeleteAlignReference(OutFH):
256 """Delete alignment reference object."""
257
258 RefName = OptionsInfo["RefFileInfo"]["PyMOLObjectName"]
259 OutFH.write("""\n""\n"Deleting alignment reference object %s..."\n""\n""" % RefName)
260 OutFH.write("""cmd.delete("%s")\n""" % RefName)
261
262
263 def WriteComplexView(OutFH, FileIndex, PyMOLObjectNames, FirstComplex):
264 """Write out PML for viewing polymer complex along with cryo-EM density."""
265
266 # Setup complex...
267 Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
268 PML = PyMOLUtil.SetupPMLForPolymerComplexView(PyMOLObjectNames["Complex"], Infile, True)
269 OutFH.write("""\n""\n"Loading %s and setting up view for complex..."\n""\n""" % Infile)
270 OutFH.write("%s\n" % PML)
271
272 if OptionsInfo["Align"]:
273 # No need to align complex on to itself...
274 if not (re.match("^FirstInputFile$", OptionsInfo["AlignRefFile"], re.I) and FirstComplex):
275 WriteAlignComplex(OutFH, FileIndex, PyMOLObjectNames)
276
277 # Setup cryo-EM density maps and meshes...
278 DensityMapFile = OptionsInfo["DensityMapFilesNames"][FileIndex]
279 ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
280 WriteComplexCryoEMDensityMapView(OutFH, PyMOLObjectNames, DensityMapFile, ContourLevel)
281
282 # Setup complex group...
283 GenerateAndWritePMLForGroup(
284 OutFH, PyMOLObjectNames["ComplexGroup"], PyMOLObjectNames["ComplexGroupMembers"], False, "close"
285 )
286
287
288 def WriteComplexCryoEMDensityMapView(OutFH, PyMOLObjectNames, MapFileName, ContourLevel):
289 """Write out PML for viewing cryoEM density map."""
290
291 # Load cryo-EM density map and setup mesh views...
292 Info = (
293 """\
294 ""
295 "Loading cryo-EM density map %s and setting up mesh view for complex..."
296 "" """
297 % MapFileName
298 )
299 OutFH.write("\n%s\n" % Info)
300
301 MapName = PyMOLObjectNames["ComplexCryoEMMap"]
302 ComplexName = PyMOLObjectNames["Complex"]
303
304 Color = OptionsInfo["MeshColor"]
305 VolumeColorRamp = OptionsInfo["VolumeColorRampName"]
306
307 VolumeName = PyMOLObjectNames["ComplexCryoEMVolume"]
308 MeshName = PyMOLObjectNames["ComplexCryoEMMesh"]
309 SurfaceName = PyMOLObjectNames["ComplexCryoEMSurface"]
310
311 AlignMapToObjectName = ComplexName if OptionsInfo["Align"] else None
312 EnableMap = True
313 PML = SetupPMLForCryoEMDensityMap(MapFileName, MapName, AlignMapToObjectName, EnableMap)
314 OutFH.write("%s\n" % PML)
315
316 EnableMesh = OptionsInfo["MeshComplex"]
317
318 EnableVolume = OptionsInfo["VolumeComplex"]
319 if EnableVolume and EnableMesh:
320 EnableVolume = False
321
322 EnableSurface = OptionsInfo["SurfaceComplex"]
323 if EnableSurface and (EnableVolume or EnableMesh):
324 EnableSurface = False
325
326 if OptionsInfo["VolumeComplex"]:
327 PML = SetupPMLForCryoEMDensityVolume(
328 MapName, VolumeName, VolumeColorRamp, Enable=EnableVolume, Selection=ComplexName
329 )
330 OutFH.write("\n%s\n" % PML)
331
332 if OptionsInfo["MeshComplex"]:
333 PML = SetupPMLForCryoEMDensityMesh(
334 MapName, MeshName, ContourLevel, Color, Enable=EnableMesh, Selection=ComplexName
335 )
336 OutFH.write("\n%s\n" % PML)
337
338 if OptionsInfo["SurfaceComplex"]:
339 PML = SetupPMLForCryoEMDensitySurface(
340 MapName, SurfaceName, ContourLevel, Color, Enable=EnableSurface, Selection=ComplexName
341 )
342 OutFH.write("\n%s\n" % PML)
343
344 GenerateAndWritePMLForGroup(
345 OutFH, PyMOLObjectNames["ComplexCryoEMGroup"], PyMOLObjectNames["ComplexCryoEMGroupMembers"], True, "close"
346 )
347
348
349 def WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
350 """Write out PML for viewing chain."""
351
352 OutFH.write("""\n""\n"Setting up views for chain %s..."\n""\n""" % ChainID)
353
354 ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
355
356 # Setup chain complex group view...
357 WriteChainComplexAndMeshViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
358
359 # Setup chain view...
360 WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
361
362 # Setup chain solvent view...
363 PML = PyMOLUtil.SetupPMLForSolventView(PyMOLObjectNames["Chains"][ChainID]["Solvent"], ChainComplexName, False)
364 OutFH.write("\n%s\n" % PML)
365
366 # Setup chain inorganic view...
367 PML = PyMOLUtil.SetupPMLForInorganicView(PyMOLObjectNames["Chains"][ChainID]["Inorganic"], ChainComplexName, False)
368 OutFH.write("\n%s\n" % PML)
369
370
371 def WriteChainComplexAndMeshViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
372 """Write chain complex and mesh views."""
373
374 # Setup chain complex...
375 ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
376 PML = PyMOLUtil.SetupPMLForPolymerChainComplexView(ChainComplexName, PyMOLObjectNames["Complex"], ChainID, True)
377 OutFH.write("%s\n" % PML)
378
379 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
380
381 MeshChainComplex = SpecifiedChainsAndLigandsInfo["MeshChainComplex"][ChainID]
382 VolumeChainComplex = SpecifiedChainsAndLigandsInfo["VolumeChainComplex"][ChainID]
383 SurfaceChainComplex = SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"][ChainID]
384
385 EnableVolumeChainComplex = SpecifiedChainsAndLigandsInfo["EnableVolumeChainComplex"][ChainID]
386 EnableMeshChainComplex = SpecifiedChainsAndLigandsInfo["EnableMeshChainComplex"][ChainID]
387 EnableSurfaceChainComplex = SpecifiedChainsAndLigandsInfo["EnableSurfaceChainComplex"][ChainID]
388
389 if MeshChainComplex or VolumeChainComplex or SurfaceChainComplex:
390 # Set up cryoEM mesh and group...
391 MapName = PyMOLObjectNames["ComplexCryoEMMap"]
392 ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
393 Color = OptionsInfo["MeshColor"]
394
395 VolumeColorRamp = OptionsInfo["VolumeColorRampName"]
396
397 VolumeName = PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMVolume"]
398 MeshName = PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMMesh"]
399 SurfaceName = PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMSurface"]
400
401 if VolumeChainComplex:
402 PML = SetupPMLForCryoEMDensityVolume(
403 MapName, VolumeName, VolumeColorRamp, Enable=EnableVolumeChainComplex, Selection=ChainComplexName
404 )
405 OutFH.write("\n%s\n" % PML)
406
407 if MeshChainComplex:
408 PML = SetupPMLForCryoEMDensityMesh(
409 MapName, MeshName, ContourLevel, Color, Enable=EnableMeshChainComplex, Selection=ChainComplexName
410 )
411 OutFH.write("\n%s\n" % PML)
412
413 if SurfaceChainComplex:
414 PML = SetupPMLForCryoEMDensitySurface(
415 MapName, SurfaceName, ContourLevel, Color, Enable=EnableSurfaceChainComplex, Selection=ChainComplexName
416 )
417 OutFH.write("\n%s\n" % PML)
418
419 GenerateAndWritePMLForGroup(
420 OutFH,
421 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroup"],
422 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"],
423 True,
424 "close",
425 )
426
427 # Setup chain complex group...
428 EnableChainComplexGroup = SpecifiedChainsAndLigandsInfo["EnableChainComplexGroup"][ChainID]
429 GenerateAndWritePMLForGroup(
430 OutFH,
431 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"],
432 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"],
433 EnableChainComplexGroup,
434 "close",
435 )
436
437
438 def WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
439 """Write individual chain views."""
440
441 ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
442
443 # Setup chain view...
444 ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
445 PML = PyMOLUtil.SetupPMLForPolymerChainView(ChainName, ChainComplexName, Enable=True)
446 OutFH.write("\n%s\n" % PML)
447
448 # Setup chain putty by B-factor view...
449 if OptionsInfo["BFactorChainCartoonPutty"]:
450 BFactorPuttyName = PyMOLObjectNames["Chains"][ChainID]["ChainAloneBFactorPutty"]
451 PML = PyMOLUtil.SetupPMLForBFactorPuttyView(
452 BFactorPuttyName, ChainName, ColorPalette=OptionsInfo["BFactorColorPalette"], Enable=False
453 )
454 OutFH.write("\n%s\n" % PML)
455
456 # Setup chain selections view...
457 SetupChainSelectionsView(OutFH, FileIndex, PyMOLObjectNames, ChainID)
458
459 # Setup chain group...
460 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
461 EnableChainAloneGroup = SpecifiedChainsAndLigandsInfo["EnableChainAloneGroup"][ChainID]
462 GenerateAndWritePMLForGroup(
463 OutFH,
464 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"],
465 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"],
466 EnableChainAloneGroup,
467 "close",
468 )
469
470
471 def SetupChainSelectionsView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
472 """Setup chain selectons view."""
473
474 if not OptionsInfo["ChainSelections"]:
475 return
476
477 ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
478 SelectionsGroupIDPrefix = "ChainAloneSelections"
479
480 for Index in range(0, len(OptionsInfo["ChainSelectionsInfo"]["Names"])):
481 SelectionName = OptionsInfo["ChainSelectionsInfo"]["Names"][Index]
482 SpecifiedSelection = OptionsInfo["ChainSelectionsInfo"]["Selections"][Index]
483
484 SelectionNameGroupID = SelectionName
485
486 # Setup selection object...
487 SelectionObjectID = "%s%sSelection" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
488 SelectionObjectName = PyMOLObjectNames["Chains"][ChainID][SelectionObjectID]
489 SelectionCmd = "(%s and (%s))" % (ChainName, SpecifiedSelection)
490 PML = PyMOLUtil.SetupPMLForSelectionDisplayView(
491 SelectionObjectName, SelectionCmd, OptionsInfo["SelectionsChainStyle"], Enable=True
492 )
493 OutFH.write("\n%s\n" % PML)
494
495 # Set up cryo-EM mesh and group...
496 CryoEMVolumeID = "%s%sCryoEMVolume" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
497 CryoEMMeshID = "%s%sCryoEMMesh" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
498 CryoEMSurfaceID = "%s%sCryoEMSurface" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
499 CryoEMMeshGroupID = "%s%sCryoEMGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
500 CryoEMMeshGroupMembersID = "%s%sCryoEMGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
501
502 CryoEMVolumeName = PyMOLObjectNames["Chains"][ChainID][CryoEMVolumeID]
503 CryoEMMeshName = PyMOLObjectNames["Chains"][ChainID][CryoEMMeshID]
504 CryoEMSurfaceName = PyMOLObjectNames["Chains"][ChainID][CryoEMSurfaceID]
505 CryoEMMeshGroupName = PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupID]
506 CryoEMMeshGroupMembers = PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID]
507
508 MapName = PyMOLObjectNames["ComplexCryoEMMap"]
509 ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
510 Color = OptionsInfo["MeshColor"]
511
512 PML = SetupPMLForCryoEMDensityVolume(
513 MapName, CryoEMVolumeName, OptionsInfo["VolumeColorRampName"], Enable=False, Selection=SelectionObjectName
514 )
515 OutFH.write("\n%s\n" % PML)
516
517 PML = SetupPMLForCryoEMDensityMesh(
518 MapName, CryoEMMeshName, ContourLevel, Color, Enable=True, Selection=SelectionObjectName
519 )
520 OutFH.write("\n%s\n" % PML)
521
522 PML = SetupPMLForCryoEMDensitySurface(
523 MapName, CryoEMSurfaceName, ContourLevel, Color, Enable=False, Selection=SelectionObjectName
524 )
525 OutFH.write("\n%s\n" % PML)
526
527 GenerateAndWritePMLForGroup(OutFH, CryoEMMeshGroupName, CryoEMMeshGroupMembers, True, "close")
528
529 # Setup groups for named selections...
530 SelectionsNameGroupID = "%s%sGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
531 SelectionsNameGroupMembersID = "%s%sGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
532 GenerateAndWritePMLForGroup(
533 OutFH,
534 PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupID],
535 PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID],
536 True,
537 "open",
538 )
539
540 # Setup a group for selections...
541 SelectionsGroupID = "%sGroup" % (SelectionsGroupIDPrefix)
542 SelectionsGroupMembersID = "%sGroupMembers" % (SelectionsGroupIDPrefix)
543 GenerateAndWritePMLForGroup(
544 OutFH,
545 PyMOLObjectNames["Chains"][ChainID][SelectionsGroupID],
546 PyMOLObjectNames["Chains"][ChainID][SelectionsGroupMembersID],
547 False,
548 "close",
549 )
550
551
552 def WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID):
553 """Write out PML for viewing ligand in a chain."""
554
555 for GroupID in ["Ligand", "Pocket", "PocketSolvent", "PocketInorganic"]:
556 ComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
557 LigandName = PyMOLObjectNames["Ligands"][ChainID][LigandID]["Ligand"]
558
559 # Setup main object...
560 GroupTypeObjectID = "%s" % (GroupID)
561 GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
562
563 if re.match("^Ligand$", GroupID, re.I):
564 OutFH.write("""\n""\n"Setting up views for ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
565 PML = PyMOLUtil.SetupPMLForLigandView(
566 GroupTypeObjectName, ComplexName, LigandID, Enable=True, IgnoreHydrogens=OptionsInfo["IgnoreHydrogens"]
567 )
568 OutFH.write("%s\n" % PML)
569 elif re.match("^Pocket$", GroupID, re.I):
570 OutFH.write(
571 """\n""\n"Setting up views for pocket around ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID)
572 )
573 PML = PyMOLUtil.SetupPMLForLigandPocketView(
574 GroupTypeObjectName,
575 ComplexName,
576 LigandName,
577 OptionsInfo["PocketDistanceCutoff"],
578 Enable=True,
579 IgnoreHydrogens=OptionsInfo["IgnoreHydrogens"],
580 )
581 OutFH.write("%s\n" % PML)
582 OutFH.write(
583 """cmd.set("label_color", "%s", "%s")\n""" % (OptionsInfo["PocketLabelColor"], GroupTypeObjectName)
584 )
585 elif re.match("^PocketSolvent$", GroupID, re.I):
586 OutFH.write(
587 """\n""\n"Setting up views for solvent in pockect around ligand %s in chain %s..."\n""\n"""
588 % (LigandID, ChainID)
589 )
590 PML = PyMOLUtil.SetupPMLForLigandPocketSolventView(
591 GroupTypeObjectName, ComplexName, LigandName, OptionsInfo["PocketDistanceCutoff"], Enable=True
592 )
593 OutFH.write("%s\n" % PML)
594 elif re.match("^PocketInorganic$", GroupID, re.I):
595 OutFH.write(
596 """\n""\n"Setting up views for inorganic in pockect around ligand %s in chain %s..."\n""\n"""
597 % (LigandID, ChainID)
598 )
599 PML = PyMOLUtil.SetupPMLForLigandPocketInorganicView(
600 GroupTypeObjectName, ComplexName, LigandName, OptionsInfo["PocketDistanceCutoff"], Enable=True
601 )
602 OutFH.write("%s\n" % PML)
603
604 # Set up cryoEM mesh and group...
605 CryoEMMeshGroupID = "%sCryoEMMeshGroup" % (GroupID)
606 CryoEMMeshGroupMembersID = "%sCryoEMMeshGroupMembers" % (GroupID)
607 CryoEMVolumeID = "%sCryoEMVolume" % (GroupID)
608 CryoEMMeshID = "%sCryoEMMesh" % (GroupID)
609 CryoEMSurfaceID = "%sCryoEMSurface" % (GroupID)
610
611 CryoEMMapName = PyMOLObjectNames["ComplexCryoEMMap"]
612 CryoEMVolumeName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMVolumeID]
613 CryoEMMeshName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshID]
614 CryoEMSurfaceName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMSurfaceID]
615 CryoEMMeshGroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupID]
616 CryoEMMeshGroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID]
617
618 PML = SetupPMLForCryoEMDensityVolume(
619 CryoEMMapName,
620 CryoEMVolumeName,
621 OptionsInfo["VolumeColorRampName"],
622 Enable=False,
623 Selection=GroupTypeObjectName,
624 )
625 OutFH.write("\n%s\n" % PML)
626
627 ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
628 PML = SetupPMLForCryoEMDensityMesh(
629 CryoEMMapName,
630 CryoEMMeshName,
631 ContourLevel,
632 OptionsInfo["MeshColor"],
633 Enable=True,
634 Selection=GroupTypeObjectName,
635 )
636 OutFH.write("\n%s\n" % PML)
637
638 PML = SetupPMLForCryoEMDensitySurface(
639 CryoEMMapName,
640 CryoEMSurfaceName,
641 ContourLevel,
642 OptionsInfo["MeshColor"],
643 Enable=False,
644 Selection=GroupTypeObjectName,
645 )
646 OutFH.write("\n%s\n" % PML)
647
648 GenerateAndWritePMLForGroup(OutFH, CryoEMMeshGroupName, CryoEMMeshGroupMembers, True, "close")
649
650 # Set up polar contacts...
651 if re.match("^(Pocket|PocketSolvent|PocketInorganic)$", GroupID, re.I):
652 PolarContactsID = "%sPolarContacts" % (GroupID)
653 PolarContactsName = PyMOLObjectNames["Ligands"][ChainID][LigandID][PolarContactsID]
654
655 PolarContactsColor = OptionsInfo["PocketContactsLigandColor"]
656 if re.match("^PocketSolvent$", GroupID, re.I):
657 PolarContactsColor = OptionsInfo["PocketContactsSolventColor"]
658 elif re.match("^PocketInorganic$", GroupID, re.I):
659 PolarContactsColor = OptionsInfo["PocketContactsInorganicColor"]
660
661 PML = PyMOLUtil.SetupPMLForPolarContactsView(
662 PolarContactsName,
663 LigandName,
664 GroupTypeObjectName,
665 Enable=False,
666 Color=PolarContactsColor,
667 Cutoff=OptionsInfo["PocketContactsCutoff"],
668 )
669 OutFH.write("\n%s\n" % PML)
670
671 OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (PolarContactsColor, PolarContactsName))
672
673 # Set up hydrophobic contacts...
674 if re.match("^Pocket$", GroupID, re.I):
675 HydrophobicContactsID = "%sHydrophobicContacts" % (GroupID)
676 HydrophobicContactsName = PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicContactsID]
677 HydrophobicContactsColor = OptionsInfo["PocketContactsLigandHydrophobicColor"]
678
679 PML = PyMOLUtil.SetupPMLForHydrophobicContactsView(
680 HydrophobicContactsName,
681 LigandName,
682 GroupTypeObjectName,
683 Enable=False,
684 Color=HydrophobicContactsColor,
685 Cutoff=OptionsInfo["PocketContactsCutoff"],
686 )
687 OutFH.write("\n%s\n" % PML)
688 OutFH.write(
689 """cmd.set("label_color", "%s", "%s")\n""" % (HydrophobicContactsColor, HydrophobicContactsName)
690 )
691
692 # Set up hydrophobic surface...
693 if re.match("^Pocket$", GroupID, re.I) and OptionsInfo["PocketSurface"]:
694 HydrophobicSurfaceID = "%sHydrophobicSurface" % (GroupID)
695 HydrophobicSurfaceName = PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicSurfaceID]
696 PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
697 HydrophobicSurfaceName, GroupTypeObjectName, ColorPalette="RedToWhite", Enable=False
698 )
699 OutFH.write("\n%s\n" % PML)
700
701 OutFH.write(
702 """cmd.set("label_color", "%s", "%s")\n""" % (OptionsInfo["PocketLabelColor"], HydrophobicSurfaceName)
703 )
704
705 # Setup group....
706 GroupNameID = "%sGroup" % (GroupID)
707 GroupMembersID = "%sGroupMembers" % (GroupID)
708 GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
709 GroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID]
710
711 Action = "close"
712 Enable = False
713 if re.match("^(Ligand|Pocket)$", GroupID, re.I):
714 Action = "open"
715 Enable = True
716 GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable, Action)
717
718
719 def GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable=False, Action="close"):
720 """Generate and write PML for group."""
721
722 PML = PyMOLUtil.SetupPMLForGroup(GroupName, GroupMembers, Enable, Action)
723 OutFH.write("""\n""\n"Setting up group %s..."\n""\n""" % GroupName)
724 OutFH.write("%s\n" % PML)
725
726
727 def SetupPMLForCryoEMDensityMap(MapFileName, MapName, AlignMapToObjectName=None, Enable=True):
728 """Setup PML for loading and viewing cryo-EM density map."""
729
730 PMLCmds = []
731 PMLCmds.append("""cmd.load("%s", "%s")""" % (MapFileName, MapName))
732 if AlignMapToObjectName is not None:
733 PMLCmds.append("""cmd.matrix_copy("%s", "%s")""" % (AlignMapToObjectName, MapName))
734
735 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MapName, Enable))
736
737 PML = "\n".join(PMLCmds)
738
739 return PML
740
741
742 def SetupPMLForCryoEMDensityMesh(MapName, MeshName, SigmaLevel, Color, Enable=True, Selection=None):
743 """Setup PML for cryo-EM density mesh."""
744
745 Carve = OptionsInfo["MeshCarveRadius"]
746
747 PMLCmds = []
748 if Selection is None:
749 PMLCmds.append("""cmd.isomesh("%s", "%s", %.1f)""" % (MeshName, MapName, SigmaLevel))
750 else:
751 PMLCmds.append(
752 """cmd.isomesh("%s", "%s", %.1f, "(%s)", carve = %.1f)"""
753 % (MeshName, MapName, SigmaLevel, Selection, Carve)
754 )
755 PMLCmds.append(PyMOLUtil.SetupPMLForDeepColoring(MeshName, Color))
756 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MeshName, Enable))
757
758 PML = "\n".join(PMLCmds)
759
760 return PML
761
762
763 def SetupPMLForCryoEMDensityVolume(MapName, VolumeName, VolumeColorRamp, Enable=True, Selection=None):
764 """Setup PML for cryo-EM density volume."""
765
766 Carve = OptionsInfo["VolumeCarveRadius"]
767
768 PMLCmds = []
769 if Selection is None:
770 PMLCmds.append("""cmd.volume("%s", "%s", "%s")""" % (VolumeName, MapName, VolumeColorRamp))
771 else:
772 PMLCmds.append(
773 """cmd.volume("%s", "%s", "%s", "(%s)", carve = %.1f)"""
774 % (VolumeName, MapName, VolumeColorRamp, Selection, Carve)
775 )
776 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(VolumeName, Enable))
777
778 PML = "\n".join(PMLCmds)
779
780 return PML
781
782
783 def SetupPMLForCryoEMDensitySurface(MapName, SurfaceName, SigmaLevel, Color, Enable=True, Selection=None):
784 """Setup PML for cryo-EM density surface."""
785
786 Carve = OptionsInfo["MeshCarveRadius"]
787
788 PMLCmds = []
789 if Selection is None:
790 PMLCmds.append("""cmd.isosurface("%s", "%s", %.1f)""" % (SurfaceName, MapName, SigmaLevel))
791 else:
792 PMLCmds.append(
793 """cmd.isosurface("%s", "%s", %.1f, "(%s)", carve = %.1f)"""
794 % (SurfaceName, MapName, SigmaLevel, Selection, Carve)
795 )
796 PMLCmds.append(PyMOLUtil.SetupPMLForDeepColoring(SurfaceName, Color))
797 PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(SurfaceName, Enable))
798
799 PML = "\n".join(PMLCmds)
800
801 return PML
802
803
804 def GeneratePyMOLSessionFile():
805 """Generate PME file from PML file."""
806
807 PSEOutfile = OptionsInfo["PSEOutfile"]
808 PMLOutfile = OptionsInfo["PMLOutfile"]
809
810 MiscUtil.PrintInfo("\nGenerating file %s..." % PSEOutfile)
811
812 PyMOLUtil.ConvertPMLFileToPSEFile(PMLOutfile, PSEOutfile)
813
814 if not os.path.exists(PSEOutfile):
815 MiscUtil.PrintWarning("Failed to generate PSE file, %s..." % (PSEOutfile))
816
817 if not OptionsInfo["PMLOut"]:
818 MiscUtil.PrintInfo("Deleting file %s..." % PMLOutfile)
819 os.remove(PMLOutfile)
820
821
822 def DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames):
823 """Delete empty PyMOL objects."""
824
825 if OptionsInfo["AllowEmptyObjects"]:
826 return
827
828 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
829 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
830 OutFH.write("""\n""\n"Checking and deleting empty objects for chain %s..."\n""\n""" % (ChainID))
831
832 # Delete any chain level objects...
833 WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Solvent"])
834 WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Inorganic"])
835
836 for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
837 # Delete ligand level objects...
838 for GroupID in ["Pocket", "PocketSolvent", "PocketInorganic"]:
839 GroupNameID = "%sGroup" % (GroupID)
840 GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
841
842 GroupTypeObjectID = "%s" % (GroupID)
843 GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
844
845 WritePMLToCheckAndDeleteEmptyObjects(OutFH, GroupTypeObjectName, GroupName)
846
847
848 def WritePMLToCheckAndDeleteEmptyObjects(OutFH, ObjectName, ParentObjectName=None):
849 """Write PML to check and delete empty PyMOL objects."""
850
851 if ParentObjectName is None:
852 PML = """CheckAndDeleteEmptyObjects("%s")""" % (ObjectName)
853 else:
854 PML = """CheckAndDeleteEmptyObjects("%s", "%s")""" % (ObjectName, ParentObjectName)
855
856 OutFH.write("%s\n" % PML)
857
858
859 def SetupPyMOLObjectNames(FileIndex):
860 """Setup hierarchy of PyMOL groups and objects for ligand centric views of
861 cryo-EM density for chains and ligands present in input file.
862 """
863
864 PyMOLObjectNames = {}
865 PyMOLObjectNames["Chains"] = {}
866 PyMOLObjectNames["Ligands"] = {}
867
868 # Setup groups and objects for complex...
869 SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames)
870
871 # Setup groups and objects for chain...
872 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
873 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
874 SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID)
875
876 # Setup groups and objects for ligand...
877 for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
878 SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID)
879
880 return PyMOLObjectNames
881
882
883 def SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames):
884 """Stetup groups and objects for complex."""
885
886 PDBFileRoot = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
887
888 PDBGroupName = "%s" % PDBFileRoot
889 PyMOLObjectNames["PDBGroup"] = PDBGroupName
890 PyMOLObjectNames["PDBGroupMembers"] = []
891
892 ComplexGroupName = "%s.Complex" % PyMOLObjectNames["PDBGroup"]
893 PyMOLObjectNames["ComplexGroup"] = ComplexGroupName
894 PyMOLObjectNames["PDBGroupMembers"].append(ComplexGroupName)
895
896 PyMOLObjectNames["Complex"] = "%s.Complex" % ComplexGroupName
897
898 CryoEMMeshGroupName = "%s.CryoEM" % (ComplexGroupName)
899 CryoEMMapName = "%s.Map" % (CryoEMMeshGroupName)
900 CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
901 CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
902 CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
903
904 PyMOLObjectNames["ComplexCryoEMGroup"] = CryoEMMeshGroupName
905 PyMOLObjectNames["ComplexCryoEMMap"] = CryoEMMapName
906 PyMOLObjectNames["ComplexCryoEMVolume"] = CryoEMVolumeName
907 PyMOLObjectNames["ComplexCryoEMMesh"] = CryoEMMeshName
908 PyMOLObjectNames["ComplexCryoEMSurface"] = CryoEMSurfaceName
909
910 PyMOLObjectNames["ComplexCryoEMGroupMembers"] = []
911 PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMMapName)
912 if OptionsInfo["VolumeComplex"]:
913 PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMVolumeName)
914 if OptionsInfo["MeshComplex"]:
915 PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMMeshName)
916 if OptionsInfo["SurfaceComplex"]:
917 PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMSurfaceName)
918
919 PyMOLObjectNames["ComplexGroupMembers"] = []
920 PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["Complex"])
921 PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["ComplexCryoEMGroup"])
922
923
924 def SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID):
925 """Setup groups and objects for chain."""
926
927 PDBGroupName = PyMOLObjectNames["PDBGroup"]
928
929 SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
930 MeshChainComplex = SpecifiedChainsAndLigandsInfo["MeshChainComplex"][ChainID]
931 VolumeChainComplex = SpecifiedChainsAndLigandsInfo["VolumeChainComplex"][ChainID]
932 SurfaceChainComplex = SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"][ChainID]
933
934 PyMOLObjectNames["Chains"][ChainID] = {}
935 PyMOLObjectNames["Ligands"][ChainID] = {}
936
937 # Set up chain group and chain objects...
938 ChainGroupName = "%s.Chain%s" % (PDBGroupName, ChainID)
939 PyMOLObjectNames["Chains"][ChainID]["ChainGroup"] = ChainGroupName
940 PyMOLObjectNames["PDBGroupMembers"].append(ChainGroupName)
941 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"] = []
942
943 # Setup chain complex group and objects...
944 ChainComplexGroupName = "%s.Complex" % (ChainGroupName)
945 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"] = ChainComplexGroupName
946 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainComplexGroupName)
947
948 PyMOLObjectNames["Chains"][ChainID]["ChainComplex"] = "%s.Complex" % (ChainComplexGroupName)
949
950 CryoEMMeshGroupName = "%s.CryoEM" % (ChainComplexGroupName)
951 CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
952 CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
953 CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
954
955 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroup"] = CryoEMMeshGroupName
956 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMVolume"] = CryoEMVolumeName
957 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMMesh"] = CryoEMMeshName
958 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMSurface"] = CryoEMSurfaceName
959
960 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"] = []
961 if VolumeChainComplex:
962 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"].append(CryoEMVolumeName)
963 if MeshChainComplex:
964 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"].append(CryoEMMeshName)
965 if SurfaceChainComplex:
966 PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"].append(CryoEMSurfaceName)
967
968 NameIDs = ["ChainComplex"]
969 if MeshChainComplex or VolumeChainComplex or SurfaceChainComplex:
970 NameIDs.append("ChainComplexCryoEMGroup")
971
972 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"] = []
973 for NameID in NameIDs:
974 Name = PyMOLObjectNames["Chains"][ChainID][NameID]
975 PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
976
977 # Setup up a group for individual chains...
978 ChainAloneGroupName = "%s.Chain" % (ChainGroupName)
979 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"] = ChainAloneGroupName
980 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainAloneGroupName)
981
982 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"] = []
983
984 Name = "%s.Chain" % (ChainAloneGroupName)
985 PyMOLObjectNames["Chains"][ChainID]["ChainAlone"] = Name
986 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
987
988 if OptionsInfo["BFactorChainCartoonPutty"]:
989 Name = "%s.BFactor" % (ChainAloneGroupName)
990 PyMOLObjectNames["Chains"][ChainID]["ChainAloneBFactorPutty"] = Name
991 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
992
993 if OptionsInfo["ChainSelections"]:
994 # Setup selections group and its subgroups..
995 SelectionsGroupName = "%s.Selections" % (ChainAloneGroupName)
996
997 SelectionsGroupIDPrefix = "ChainAloneSelections"
998 SelectionsGroupID = "%sGroup" % SelectionsGroupIDPrefix
999
1000 # Add selections group to chain alone group...
1001 PyMOLObjectNames["Chains"][ChainID][SelectionsGroupID] = SelectionsGroupName
1002 PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(SelectionsGroupName)
1003
1004 # Initialize selections group members...
1005 SelectionsGroupMembersID = "%sGroupMembers" % SelectionsGroupIDPrefix
1006 PyMOLObjectNames["Chains"][ChainID][SelectionsGroupMembersID] = []
1007
1008 # Setup selections name sub group and its members...
1009 for SelectionName in OptionsInfo["ChainSelectionsInfo"]["Names"]:
1010 SelectionNameGroupID = SelectionName
1011
1012 SelectionsNameGroupName = "%s.%s" % (SelectionsGroupName, SelectionName)
1013 SelectionsNameGroupID = "%s%sGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1014
1015 # Add selections name sub group to selections group...
1016 PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupID] = SelectionsNameGroupName
1017 PyMOLObjectNames["Chains"][ChainID][SelectionsGroupMembersID].append(SelectionsNameGroupName)
1018
1019 # Initialize selections names sub group members...
1020 SelectionsNameGroupMembersID = "%s%sGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1021 PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID] = []
1022
1023 # Add selection object to selections name group...
1024 SelectionObjectName = "%s.Selection" % (SelectionsNameGroupName)
1025 SelectionObjectID = "%s%sSelection" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1026
1027 PyMOLObjectNames["Chains"][ChainID][SelectionObjectID] = SelectionObjectName
1028 PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID].append(SelectionObjectName)
1029
1030 # Setup cryo-EM mesh group and add it to selections name group...
1031 CryoEMMeshGroupName = "%s.CryoEM" % (SelectionsNameGroupName)
1032 CryoEMMeshGroupID = "%s%sCryoEMGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1033
1034 PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupID] = CryoEMMeshGroupName
1035 PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID].append(CryoEMMeshGroupName)
1036
1037 # Initialize cryo-EM mesh group members...
1038 CryoEMMeshGroupMembersID = "%s%sCryoEMGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1039 PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID] = []
1040
1041 # Setup members of cryo-EM mesh group...
1042 CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
1043 CryoEMVolumeID = "%s%sCryoEMVolume" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1044 CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
1045 CryoEMMeshID = "%s%sCryoEMMesh" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1046 CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
1047 CryoEMSurfaceID = "%s%sCryoEMSurface" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
1048
1049 PyMOLObjectNames["Chains"][ChainID][CryoEMVolumeID] = CryoEMVolumeName
1050 PyMOLObjectNames["Chains"][ChainID][CryoEMMeshID] = CryoEMMeshName
1051 PyMOLObjectNames["Chains"][ChainID][CryoEMSurfaceID] = CryoEMSurfaceName
1052
1053 PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID].append(CryoEMVolumeName)
1054 PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID].append(CryoEMMeshName)
1055 PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID].append(CryoEMSurfaceName)
1056
1057 # Setup solvent and inorganic objects for chain...
1058 for NameID in ["Solvent", "Inorganic"]:
1059 Name = "%s.%s" % (ChainGroupName, NameID)
1060 PyMOLObjectNames["Chains"][ChainID][NameID] = Name
1061 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(Name)
1062
1063
1064 def SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID):
1065 """Stetup groups and objects for ligand."""
1066
1067 PyMOLObjectNames["Ligands"][ChainID][LigandID] = {}
1068
1069 ChainGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainGroup"]
1070
1071 # Setup a chain level ligand group...
1072 ChainLigandGroupName = "%s.Ligand%s" % (ChainGroupName, LigandID)
1073 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"] = ChainLigandGroupName
1074 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainLigandGroupName)
1075
1076 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"] = []
1077
1078 # Set up groups and objects for a specific ligand group...
1079 for GroupType in ["Ligand", "Pocket", "Pocket_Solvent", "Pocket_Inorganic"]:
1080 GroupID = re.sub("_", "", GroupType)
1081 GroupName = "%s.%s" % (ChainLigandGroupName, GroupType)
1082
1083 GroupNameID = "%sGroup" % (GroupID)
1084 GroupMembersID = "%sGroupMembers" % (GroupID)
1085
1086 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID] = GroupName
1087 PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"].append(GroupName)
1088
1089 GroupTypeObjectName = "%s.%s" % (GroupName, GroupType)
1090 GroupTypeObjectID = "%s" % (GroupID)
1091 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID] = GroupTypeObjectName
1092
1093 CryoEMMeshGroupName = "%s.CryoEM" % (GroupName)
1094 CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
1095 CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
1096 CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
1097
1098 CryoEMMeshGroupID = "%sCryoEMMeshGroup" % (GroupID)
1099 CryoEMMeshGroupMembersID = "%sCryoEMMeshGroupMembers" % (GroupID)
1100 CryoEMVolumeID = "%sCryoEMVolume" % (GroupID)
1101 CryoEMMeshID = "%sCryoEMMesh" % (GroupID)
1102 CryoEMSurfaceID = "%sCryoEMSurface" % (GroupID)
1103
1104 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupID] = CryoEMMeshGroupName
1105 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMVolumeID] = CryoEMVolumeName
1106 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshID] = CryoEMMeshName
1107 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMSurfaceID] = CryoEMSurfaceName
1108 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID] = []
1109 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID].append(CryoEMVolumeName)
1110 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID].append(CryoEMMeshName)
1111 PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID].append(CryoEMSurfaceName)
1112
1113 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID] = []
1114 NameIDs = [GroupTypeObjectID, CryoEMMeshGroupID]
1115
1116 for NameID in NameIDs:
1117 Name = PyMOLObjectNames["Ligands"][ChainID][LigandID][NameID]
1118 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(Name)
1119
1120 if re.match("^Ligand$", GroupType, re.I):
1121 # No other object needed for Ligand group...
1122 continue
1123
1124 PolarContactsName = "%s.Polar_Contacts" % (GroupName)
1125 PolarContactsID = "%sPolarContacts" % (GroupID)
1126 PyMOLObjectNames["Ligands"][ChainID][LigandID][PolarContactsID] = PolarContactsName
1127 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(PolarContactsName)
1128
1129 if not re.match("^Pocket$", GroupType, re.I):
1130 # No other object needed for any other group besides Pocket...
1131 continue
1132
1133 if not OptionsInfo["PocketSurface"]:
1134 continue
1135
1136 HydrophobicContactsName = "%s.Hydrophobic_Contacts" % (GroupName)
1137 HydrophobicContactsID = "%sHydrophobicContacts" % (GroupID)
1138 PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicContactsID] = HydrophobicContactsName
1139 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(HydrophobicContactsName)
1140
1141 HydrophobicSurfaceName = "%s.Surface" % (GroupName)
1142 HydrophobicSurfaceID = "%sHydrophobicSurface" % (GroupID)
1143 PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicSurfaceID] = HydrophobicSurfaceName
1144 PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(HydrophobicSurfaceName)
1145
1146
1147 def ProcessDensityMapFiles():
1148 """Process density map files."""
1149
1150 DensityMapFiles = OptionsInfo["DensityMapFiles"]
1151 if re.match("^auto$", DensityMapFiles, re.I):
1152 ProcessAutoDensityMapFiles()
1153 else:
1154 ProcessSpecifiedDensityMapFiles()
1155
1156
1157 def ProcessSpecifiedDensityMapFiles():
1158 """Process specified density map files."""
1159
1160 OptionsInfo["DensityMapFilesNames"] = []
1161
1162 MiscUtil.PrintInfo("\nProcessing cryo-EM density file names...")
1163
1164 DensityMapFiles = re.sub(" ", "", OptionsInfo["DensityMapFiles"])
1165 if not DensityMapFiles:
1166 MiscUtil.PrintError('No valid value specified using "--densityMapFiles" option.')
1167
1168 DensityMapFilesWords = DensityMapFiles.split(",")
1169 DensityMapFilesWordsCount = len(DensityMapFilesWords)
1170
1171 InfilesNamesCount = len(OptionsInfo["InfilesNames"])
1172
1173 if DensityMapFilesWordsCount != InfilesNamesCount:
1174 MiscUtil.PrintError(
1175 'The number of comma delimited cryo-EM density map files, %d, specified using "--DensityMapFiles" must be equal to the number of input files, %s, specified using "-i, --infiles" option.'
1176 % (DensityMapFilesWordsCount, InfilesNamesCount)
1177 )
1178
1179 for Index in range(0, InfilesNamesCount):
1180 Infile = OptionsInfo["InfilesNames"][Index]
1181 DensityMapFile = DensityMapFilesWords[Index]
1182
1183 if not os.path.exists(DensityMapFile):
1184 MiscUtil.PrintError(
1185 'The cryo-EM density ED map file, %s, specified using option "--DensityMapFiles", corresponding to input file, %s, doesn\'t exist.\n'
1186 % (DensityMapFile, Infile)
1187 )
1188
1189 OptionsInfo["DensityMapFilesNames"].append(DensityMapFile)
1190
1191
1192 def ProcessAutoDensityMapFiles():
1193 """Set up and process name of density map files."""
1194
1195 OptionsInfo["DensityMapFilesNames"] = []
1196 InfilesNamesCount = len(OptionsInfo["InfilesNames"])
1197
1198 MiscUtil.PrintInfo("\nSetting cryo-EM density file names...")
1199
1200 for Index in range(0, InfilesNamesCount):
1201 Infile = OptionsInfo["InfilesNames"][Index]
1202
1203 EMDBID = RetrieveEMDBID(Infile)
1204 if EMDBID is None:
1205 MiscUtil.PrintError(
1206 'Failed to retrieve EMDB ID from input file %s to automatically set density map file name. Use option "-d, --densityMapFiles " to specify density map file name and try again.'
1207 % Infile
1208 )
1209
1210 DensityMapFile = None
1211 MapFileRoot = "emd_%s" % EMDBID
1212 MapFile1 = "%s.map.gz" % MapFileRoot
1213 MapFile2 = "%s.map" % MapFileRoot
1214 if os.path.exists(MapFile1):
1215 DensityMapFile = MapFile1
1216 elif os.path.exists(MapFile2):
1217 DensityMapFile = MapFile2
1218 else:
1219 MiscUtil.PrintError(
1220 'Density map files %s or %s don\'t exist. Use option "-d, --densityMapFiles " to specify density map file name and try again'
1221 % (MapFile1, MapFile2)
1222 )
1223
1224 MiscUtil.PrintInfo("Setting density map file name as %s for input file %s..." % (DensityMapFile, Infile))
1225 OptionsInfo["DensityMapFilesNames"].append(DensityMapFile)
1226
1227
1228 def RetrieveRecommededContourLevel(Infile):
1229 """Retrieve recommened contour level."""
1230
1231 if Infile in OptionsInfo["InfilesRecommededContourLevels"]:
1232 RecommendedContourLevel = OptionsInfo["InfilesRecommededContourLevels"][Infile]
1233 return RecommendedContourLevel
1234
1235 RecommendedContourLevel = None
1236 EMDBID = RetrieveEMDBID(Infile)
1237 if EMDBID is None:
1238 MiscUtil.PrintWarning(
1239 "Failed to retrieve EMDB ID from input file %s to detect local header file already downloaded from EMDB server..."
1240 % Infile
1241 )
1242 OptionsInfo["InfilesRecommededContourLevels"][Infile] = RecommendedContourLevel
1243 return RecommendedContourLevel
1244
1245 MetadataHeaderFile = "emd-%s.xml" % (EMDBID)
1246 if not os.path.exists(MetadataHeaderFile):
1247 MiscUtil.PrintWarning(
1248 "Failed to find a local header file, %s, for EMDB ID %s..." % (MetadataHeaderFile, EMDBID)
1249 )
1250 OptionsInfo["InfilesRecommededContourLevels"][Infile] = RecommendedContourLevel
1251 return RecommendedContourLevel
1252
1253 MiscUtil.PrintInfo(
1254 "\nRetrieving recommeded contour level from header file, %s, for input file, %s..."
1255 % (MetadataHeaderFile, Infile)
1256 )
1257
1258 ContourLevel = None
1259 Source = None
1260 XMLTree = ElementTree.parse(MetadataHeaderFile)
1261
1262 MapElement = XMLTree.find("map")
1263 if MapElement is not None:
1264 ContourLevelElement = MapElement.find("contourLevel")
1265 if ContourLevelElement is not None:
1266 ContourLevel = ContourLevelElement.text
1267 Source = ContourLevelElement.get("source")
1268
1269 if ContourLevel is not None:
1270 if Source is None:
1271 Source = "NA"
1272 MiscUtil.PrintInfo("Retrieved recommended (Source: %s) contour level %s..." % (Source, ContourLevel))
1273 RecommendedContourLevel = ContourLevel
1274
1275 OptionsInfo["InfilesRecommededContourLevels"][Infile] = RecommendedContourLevel
1276
1277 return RecommendedContourLevel
1278
1279
1280 def RetrieveEMDBID(Infile):
1281 """Retrieve EMDB ID from input file."""
1282
1283 if Infile in OptionsInfo["InfilesEMDBIDs"]:
1284 EMDBID = OptionsInfo["InfilesEMDBIDs"][Infile]
1285 return EMDBID
1286
1287 EMDBID = None
1288 FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
1289
1290 if re.match("^pdb$", FileExt, re.I):
1291 EMDBID = RetriveEMDBIDFromPDBFile(Infile)
1292 elif re.match("^cif$", FileExt, re.I):
1293 EMDBID = RetriveEMDBIDFromCIFFile(Infile)
1294 else:
1295 EMDBID = None
1296
1297 OptionsInfo["InfilesEMDBIDs"][Infile] = EMDBID
1298
1299 return EMDBID
1300
1301
1302 def RetriveEMDBIDFromPDBFile(Infile):
1303 """Retrieve EMDB ID from PDB file."""
1304
1305 EMDBID = None
1306 InfileFH = open(Infile, "r")
1307 if InfileFH is None:
1308 MiscUtil.PrintError("Couldn't open input file: %s.\n" % (Infile))
1309
1310 MiscUtil.PrintInfo("\nRetrieving EMDB ID from input file %s..." % Infile)
1311
1312 EMDBID = None
1313 for Line in InfileFH:
1314 Line = Line.rstrip()
1315 if re.match("^REMARK", Line, re.I):
1316 if re.search("DB: EMDB", Line, re.I):
1317 for Word in Line.split(" "):
1318 # Retrieve string with EMD-
1319 if re.search("EMD-", Word, re.I):
1320 Word = Word.strip()
1321 EMDBID = re.sub("EMD-", "", Word)
1322 break
1323 break
1324 InfileFH.close()
1325
1326 return EMDBID
1327
1328
1329 def RetriveEMDBIDFromCIFFile(Infile):
1330 """Retrieve EMDB ID from CIF file."""
1331
1332 InfileFH = open(Infile, "r")
1333 if InfileFH is None:
1334 MiscUtil.PrintError("Couldn't open input file: %s.\n" % (Infile))
1335
1336 MiscUtil.PrintInfo("\nRetrieving EMDB ID from input file %s..." % Infile)
1337
1338 EMDBID = None
1339 for Line in InfileFH:
1340 Line = Line.rstrip()
1341 if re.match("^EMDB EMD", Line, re.I):
1342 for Word in Line.split(" "):
1343 # Retrieve string with EMD-
1344 if re.search("EMD-", Word, re.I):
1345 Word = Word.strip()
1346 EMDBID = re.sub("EMD-", "", Word)
1347 break
1348 break
1349 InfileFH.close()
1350
1351 return EMDBID
1352
1353
1354 def RetrieveInfilesInfo():
1355 """Retrieve information for input files."""
1356
1357 InfilesInfo = {}
1358
1359 InfilesInfo["InfilesNames"] = []
1360 InfilesInfo["InfilesRoots"] = []
1361 InfilesInfo["ChainsAndLigandsInfo"] = []
1362
1363 for Infile in OptionsInfo["InfilesNames"]:
1364 FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
1365 InfileRoot = FileName
1366
1367 ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(Infile, InfileRoot)
1368
1369 InfilesInfo["InfilesNames"].append(Infile)
1370 InfilesInfo["InfilesRoots"].append(InfileRoot)
1371 InfilesInfo["ChainsAndLigandsInfo"].append(ChainsAndLigandInfo)
1372
1373 OptionsInfo["InfilesInfo"] = InfilesInfo
1374
1375
1376 def RetrieveRefFileInfo():
1377 """Retrieve information for ref file."""
1378
1379 RefFileInfo = {}
1380 if not OptionsInfo["Align"]:
1381 OptionsInfo["RefFileInfo"] = RefFileInfo
1382 return
1383
1384 RefFile = OptionsInfo["RefFileName"]
1385
1386 FileDir, FileName, FileExt = MiscUtil.ParseFileName(RefFile)
1387 RefFileRoot = FileName
1388
1389 if re.match("^FirstInputFile$", OptionsInfo["AlignRefFile"], re.I):
1390 ChainsAndLigandInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]
1391 else:
1392 MiscUtil.PrintInfo("\nRetrieving chain and ligand information for alignment reference file %s..." % RefFile)
1393 ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(RefFile, RefFileRoot)
1394
1395 RefFileInfo["RefFileName"] = RefFile
1396 RefFileInfo["RefFileRoot"] = RefFileRoot
1397 RefFileInfo["PyMOLObjectName"] = "AlignRef_%s" % RefFileRoot
1398 RefFileInfo["ChainsAndLigandsInfo"] = ChainsAndLigandInfo
1399
1400 OptionsInfo["RefFileInfo"] = RefFileInfo
1401
1402
1403 def ProcessChainAndLigandIDs():
1404 """Process specified chain and ligand IDs for infiles."""
1405
1406 OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"] = []
1407
1408 for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
1409 MiscUtil.PrintInfo(
1410 "\nProcessing specified chain and ligand IDs for input file %s..."
1411 % OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
1412 )
1413
1414 ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
1415 SpecifiedChainsAndLigandsInfo = PyMOLUtil.ProcessChainsAndLigandsOptionsInfo(
1416 ChainsAndLigandsInfo, "-c, --chainIDs", OptionsInfo["ChainIDs"], "-l, --ligandIDs", OptionsInfo["LigandIDs"]
1417 )
1418 ProcessChainMeshesVolumesAndSurfacesOptions(SpecifiedChainsAndLigandsInfo)
1419 OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"].append(SpecifiedChainsAndLigandsInfo)
1420
1421 CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo)
1422
1423
1424 def CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo):
1425 """Check presence of valid ligand IDs."""
1426
1427 MiscUtil.PrintInfo("\nSpecified chain IDs: %s" % (", ".join(SpecifiedChainsAndLigandsInfo["ChainIDs"])))
1428
1429 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1430 if len(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]):
1431 MiscUtil.PrintInfo(
1432 "Chain ID: %s; Specified LigandIDs: %s"
1433 % (ChainID, ", ".join(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]))
1434 )
1435 else:
1436 MiscUtil.PrintInfo("Chain IDs: %s; Specified LigandIDs: None" % (ChainID))
1437 MiscUtil.PrintWarning(
1438 "No valid ligand IDs found for chain ID, %s. PyMOL groups and objects related to ligand and binding pockect won't be created."
1439 % (ChainID)
1440 )
1441
1442
1443 def RetrieveFirstChainID(FileIndex):
1444 """Get first chain ID."""
1445
1446 ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
1447
1448 FirstChainID = None
1449 if len(ChainsAndLigandsInfo["ChainIDs"]):
1450 FirstChainID = ChainsAndLigandsInfo["ChainIDs"][0]
1451
1452 return FirstChainID
1453
1454
1455 def ProcessChainMeshesVolumesAndSurfacesOptions(SpecifiedChainsAndLigandsInfo):
1456 """Process options to create meshes and surfaces for chains."""
1457
1458 SpecifiedChainsAndLigandsInfo["VolumeChainComplex"] = {}
1459 SpecifiedChainsAndLigandsInfo["MeshChainComplex"] = {}
1460 SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"] = {}
1461
1462 SpecifiedChainsAndLigandsInfo["EnableVolumeChainComplex"] = {}
1463 SpecifiedChainsAndLigandsInfo["EnableMeshChainComplex"] = {}
1464 SpecifiedChainsAndLigandsInfo["EnableSurfaceChainComplex"] = {}
1465
1466 SpecifiedChainsAndLigandsInfo["EnableChainComplexGroup"] = {}
1467 SpecifiedChainsAndLigandsInfo["EnableChainAloneGroup"] = {}
1468
1469 for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
1470 LigandsPresent = True if len(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]) else False
1471
1472 # Create and enable mesh or volume in auto mode...
1473 if re.match("^auto$", OptionsInfo["MeshChainComplex"], re.I):
1474 MeshChainComplex = False if LigandsPresent else True
1475 EnableMeshChainComplex = False if LigandsPresent else True
1476 else:
1477 MeshChainComplex = True if re.match("^Yes$", OptionsInfo["MeshChainComplex"], re.I) else False
1478 EnableMeshChainComplex = True if re.match("^Yes$", OptionsInfo["MeshChainComplex"], re.I) else False
1479
1480 if re.match("^auto$", OptionsInfo["VolumeChainComplex"], re.I):
1481 VolumeChainComplex = False if LigandsPresent else True
1482 EnableVolumeChainComplex = False if LigandsPresent else True
1483 else:
1484 VolumeChainComplex = True if re.match("^Yes$", OptionsInfo["VolumeChainComplex"], re.I) else False
1485 EnableVolumeChainComplex = True if re.match("^Yes$", OptionsInfo["VolumeChainComplex"], re.I) else False
1486
1487 if MeshChainComplex and EnableMeshChainComplex:
1488 EnableVolumeChainComplex = False
1489
1490 # Create and enable surface in auto mode based on the status of mesh and volume...
1491 if re.match("^auto$", OptionsInfo["SurfaceChainComplex"], re.I):
1492 SurfaceChainComplex = False if LigandsPresent else True
1493 EnableSurfaceChainComplex = False if LigandsPresent else True
1494
1495 if MeshChainComplex or VolumeChainComplex:
1496 SurfaceChainComplex = False
1497 EnableSurfaceChainComplex = False
1498 else:
1499 SurfaceChainComplex = True if re.match("^Yes$", OptionsInfo["SurfaceChainComplex"], re.I) else False
1500 EnableSurfaceChainComplex = True if re.match("^Yes$", OptionsInfo["SurfaceChainComplex"], re.I) else False
1501
1502 if (MeshChainComplex and EnableMeshChainComplex) or (VolumeChainComplex or EnableVolumeChainComplex):
1503 EnableSurfaceChainComplex = False
1504
1505 if LigandsPresent:
1506 EnableChainComplexGroup = False
1507 EnableChainAloneGroup = True
1508 else:
1509 EnableChainComplexGroup = True
1510 EnableChainAloneGroup = False
1511
1512 SpecifiedChainsAndLigandsInfo["VolumeChainComplex"][ChainID] = VolumeChainComplex
1513 SpecifiedChainsAndLigandsInfo["MeshChainComplex"][ChainID] = MeshChainComplex
1514 SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"][ChainID] = SurfaceChainComplex
1515
1516 SpecifiedChainsAndLigandsInfo["EnableVolumeChainComplex"][ChainID] = EnableVolumeChainComplex
1517 SpecifiedChainsAndLigandsInfo["EnableMeshChainComplex"][ChainID] = EnableMeshChainComplex
1518 SpecifiedChainsAndLigandsInfo["EnableSurfaceChainComplex"][ChainID] = EnableSurfaceChainComplex
1519
1520 SpecifiedChainsAndLigandsInfo["EnableChainComplexGroup"][ChainID] = EnableChainComplexGroup
1521 SpecifiedChainsAndLigandsInfo["EnableChainAloneGroup"][ChainID] = EnableChainAloneGroup
1522
1523
1524 def ProcessChainSelections():
1525 """Process custom selections for chains."""
1526
1527 ChainSelectionsInfo = PyMOLUtil.ProcessChainSelectionsOptionsInfo(
1528 "--selectionsChain", OptionsInfo["SelectionsChain"]
1529 )
1530 OptionsInfo["ChainSelectionsInfo"] = ChainSelectionsInfo
1531
1532 ChainSelections = True if len(OptionsInfo["ChainSelectionsInfo"]["Names"]) else False
1533 OptionsInfo["ChainSelections"] = ChainSelections
1534
1535
1536 def ProcessMeshLevel():
1537 """Process mesh level."""
1538
1539 MeshLevel = OptionsInfo["MeshLevel"]
1540
1541 if re.match("^auto$", MeshLevel, re.I):
1542 ProcessAutoMeshLevel()
1543 else:
1544 ProcessSpecifiedMeshLevel()
1545
1546
1547 def ProcessAutoMeshLevel():
1548 """Process auto mesh level."""
1549
1550 OptionsInfo["MeshLevels"] = []
1551 InfilesNamesCount = len(OptionsInfo["InfilesNames"])
1552
1553 MiscUtil.PrintInfo("\nSetting mesh levels...")
1554
1555 for Index in range(0, InfilesNamesCount):
1556 Infile = OptionsInfo["InfilesNames"][Index]
1557
1558 RecommededContourLevel = RetrieveRecommededContourLevel(Infile)
1559 if RecommededContourLevel is None:
1560 MiscUtil.PrintWarning(
1561 'Failed to retrieve recommended mesh contour level from header. It\'s being set to 1.0. Use "--meshLevel" option to specify a different contour mesh level.'
1562 )
1563 MeshLevel = 1.0
1564 else:
1565 MeshLevel = float(RecommededContourLevel)
1566 OptionsInfo["MeshLevels"].append(MeshLevel)
1567
1568
1569 def ProcessSpecifiedMeshLevel():
1570 """Process specified mesh level."""
1571
1572 MiscUtil.PrintInfo("\nProcessing mesh levels...")
1573
1574 OptionsInfo["MeshLevels"] = []
1575 InfilesNamesCount = len(OptionsInfo["InfilesNames"])
1576
1577 MeshLevels = re.sub(" ", "", OptionsInfo["MeshLevel"])
1578 if not MeshLevels:
1579 MiscUtil.PrintError('No valid value specified using "--meshLevel" option.')
1580
1581 MeshLevelWords = MeshLevels.split(",")
1582 MeshLevelWordsCount = len(MeshLevelWords)
1583
1584 if MeshLevelWordsCount != InfilesNamesCount:
1585 MiscUtil.PrintError(
1586 'The number of comma delimited mesh levels, %d, specified using "--meshLevel" must be equal to the number of input files, %s, specified using "-i, --infiles" option.'
1587 % (MeshLevelWordsCount, InfilesNamesCount)
1588 )
1589
1590 for Index in range(0, InfilesNamesCount):
1591 Infile = OptionsInfo["InfilesNames"][Index]
1592 MeshLevel = MeshLevelWords[Index]
1593 if not MiscUtil.IsFloat(MeshLevel):
1594 MiscUtil.PrintError(
1595 'The mesh level, %s, specified using "--meshLevel" for input file, %s, must be a float.'
1596 % (MeshLevel, Infile)
1597 )
1598
1599 MeshLevel = float(MeshLevel)
1600 OptionsInfo["MeshLevels"].append(MeshLevel)
1601
1602
1603 def ProcessVolumeColorRamp():
1604 """Process volume color ramp."""
1605
1606 MiscUtil.PrintInfo("\nProcessing volume color ramp...")
1607
1608 ColorRamp = Options["--volumeColorRamp"]
1609 ColorRampName = None
1610 CreateColorRamp = False
1611 ColorRampContourLevel = None
1612 if re.match("^auto$", ColorRamp, re.I):
1613 FirstInfile = OptionsInfo["InfilesNames"][0]
1614 RecommededContourLevel = RetrieveRecommededContourLevel(FirstInfile)
1615 if RecommededContourLevel is None:
1616 ColorRampName = "default"
1617 MiscUtil.PrintWarning(
1618 "Failed to retrieve recommended contour level from header file corresponding to input file, %s, to create a new ramp. Using PyMOL default volume color ramp."
1619 % (FirstInfile)
1620 )
1621 else:
1622 ColorRampName = "CryoEMAuto"
1623 CreateColorRamp = True
1624 ColorRampContourLevel = float(RecommededContourLevel)
1625 MiscUtil.PrintInfo(
1626 "\nSetting up a new volume color ramp, %s, at recommended contour level, %.2f, from input file, %s..."
1627 % (ColorRampName, ColorRampContourLevel, FirstInfile)
1628 )
1629 else:
1630 ColorRampName = ColorRamp
1631
1632 OptionsInfo["VolumeColorRamp"] = ColorRamp
1633 OptionsInfo["VolumeColorRampName"] = ColorRampName
1634 OptionsInfo["VolumeColorRampCreate"] = CreateColorRamp
1635 OptionsInfo["VolumeColorRampContourLevel"] = ColorRampContourLevel
1636
1637
1638 def ProcessOptions():
1639 """Process and validate command line arguments and options."""
1640
1641 MiscUtil.PrintInfo("Processing options...")
1642
1643 # Validate options...
1644 ValidateOptions()
1645
1646 OptionsInfo["Align"] = True if re.match("^Yes$", Options["--align"], re.I) else False
1647 OptionsInfo["AlignMethod"] = Options["--alignMethod"].lower()
1648 OptionsInfo["AlignMode"] = Options["--alignMode"]
1649
1650 OptionsInfo["AllowEmptyObjects"] = True if re.match("^Yes$", Options["--allowEmptyObjects"], re.I) else False
1651
1652 OptionsInfo["BFactorChainCartoonPutty"] = (
1653 True if re.match("^Yes$", Options["--BFactorChainCartoonPutty"], re.I) else False
1654 )
1655 OptionsInfo["BFactorColorPalette"] = Options["--BFactorColorPalette"]
1656
1657 OptionsInfo["Infiles"] = Options["--infiles"]
1658 OptionsInfo["InfilesNames"] = Options["--infileNames"]
1659
1660 OptionsInfo["InfilesEMDBIDs"] = {}
1661 OptionsInfo["InfilesRecommededContourLevels"] = {}
1662
1663 OptionsInfo["AlignRefFile"] = Options["--alignRefFile"]
1664 if re.match("^FirstInputFile$", Options["--alignRefFile"], re.I):
1665 OptionsInfo["RefFileName"] = OptionsInfo["InfilesNames"][0]
1666 else:
1667 OptionsInfo["RefFileName"] = Options["--alignRefFile"]
1668
1669 OptionsInfo["IgnoreHydrogens"] = True if re.match("^Yes$", Options["--ignoreHydrogens"], re.I) else False
1670
1671 OptionsInfo["DensityMapFiles"] = Options["--densityMapFiles"]
1672 ProcessDensityMapFiles()
1673
1674 OptionsInfo["Overwrite"] = Options["--overwrite"]
1675 OptionsInfo["PMLOut"] = True if re.match("^Yes$", Options["--PMLOut"], re.I) else False
1676
1677 OptionsInfo["Outfile"] = Options["--outfile"]
1678 FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"])
1679 OptionsInfo["PSEOut"] = False
1680 if re.match("^pml$", FileExt, re.I):
1681 OptionsInfo["PMLOutfile"] = OptionsInfo["Outfile"]
1682 OptionsInfo["PMEOutfile"] = re.sub(".pml$", ".pme", OptionsInfo["Outfile"])
1683 elif re.match("^pse$", FileExt, re.I):
1684 OptionsInfo["PSEOut"] = True
1685 OptionsInfo["PSEOutfile"] = OptionsInfo["Outfile"]
1686 OptionsInfo["PMLOutfile"] = re.sub(".pse$", ".pml", OptionsInfo["Outfile"])
1687 if os.path.exists(OptionsInfo["PMLOutfile"]) and (not OptionsInfo["Overwrite"]):
1688 MiscUtil.PrintError(
1689 'The intermediate output file to be generated, %s, already exist. Use option "--ov" or "--overwrite" and try again.'
1690 % OptionsInfo["PMLOutfile"]
1691 )
1692
1693 OptionsInfo["LabelFontID"] = int(Options["--labelFontID"])
1694
1695 # Process mesh parameters...
1696 OptionsInfo["MeshCarveRadius"] = float(Options["--meshCarveRadius"])
1697 OptionsInfo["MeshComplex"] = True if re.match("^Yes$", Options["--meshComplex"], re.I) else False
1698 OptionsInfo["MeshChainComplex"] = Options["--meshChainComplex"]
1699
1700 OptionsInfo["MeshWidth"] = float(Options["--meshWidth"])
1701 OptionsInfo["MeshColor"] = Options["--meshColor"]
1702
1703 OptionsInfo["MeshLevel"] = Options["--meshLevel"]
1704 ProcessMeshLevel()
1705
1706 OptionsInfo["SurfaceComplex"] = True if re.match("^Yes$", Options["--surfaceComplex"], re.I) else False
1707 OptionsInfo["SurfaceChainComplex"] = Options["--surfaceChainComplex"]
1708 OptionsInfo["SurfaceTransparency"] = float(Options["--surfaceTransparency"])
1709
1710 OptionsInfo["PocketContactsLigandColor"] = Options["--pocketContactsLigandColor"]
1711 OptionsInfo["PocketContactsLigandHydrophobicColor"] = Options["--pocketContactsLigandHydrophobicColor"]
1712 OptionsInfo["PocketContactsSolventColor"] = Options["--pocketContactsSolventColor"]
1713 OptionsInfo["PocketContactsInorganicColor"] = Options["--pocketContactsInorganicColor"]
1714
1715 OptionsInfo["PocketContactsCutoff"] = float(Options["--pocketContactsCutoff"])
1716 OptionsInfo["PocketDistanceCutoff"] = float(Options["--pocketDistanceCutoff"])
1717
1718 OptionsInfo["PocketLabelColor"] = Options["--pocketLabelColor"]
1719 OptionsInfo["PocketSurface"] = True if re.match("^Yes$", Options["--pocketSurface"], re.I) else False
1720
1721 OptionsInfo["SelectionsChain"] = Options["--selectionsChain"]
1722 OptionsInfo["SelectionsChainStyle"] = Options["--selectionsChainStyle"]
1723 ProcessChainSelections()
1724
1725 OptionsInfo["VolumeCarveRadius"] = float(Options["--volumeCarveRadius"])
1726 OptionsInfo["VolumeComplex"] = True if re.match("^Yes$", Options["--volumeComplex"], re.I) else False
1727 OptionsInfo["VolumeChainComplex"] = Options["--volumeChainComplex"]
1728
1729 ProcessVolumeColorRamp()
1730
1731 RetrieveInfilesInfo()
1732 RetrieveRefFileInfo()
1733
1734 OptionsInfo["ChainIDs"] = Options["--chainIDs"]
1735 OptionsInfo["LigandIDs"] = Options["--ligandIDs"]
1736
1737 ProcessChainAndLigandIDs()
1738
1739
1740 def RetrieveOptions():
1741 """Retrieve command line arguments and options."""
1742
1743 # Get options...
1744 global Options
1745 Options = docopt(_docoptUsage_)
1746
1747 # Set current working directory to the specified directory...
1748 WorkingDir = Options["--workingdir"]
1749 if WorkingDir:
1750 os.chdir(WorkingDir)
1751
1752 # Handle examples option...
1753 if "--examples" in Options and Options["--examples"]:
1754 MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
1755 sys.exit(0)
1756
1757
1758 def ValidateOptions():
1759 """Validate option values."""
1760
1761 MiscUtil.ValidateOptionTextValue("--align", Options["--align"], "yes no")
1762 MiscUtil.ValidateOptionTextValue("--alignMethod", Options["--alignMethod"], "align cealign super")
1763 MiscUtil.ValidateOptionTextValue("--alignMode", Options["--alignMode"], "FirstChain Complex")
1764
1765 MiscUtil.ValidateOptionTextValue("--allowEmptyObjects", Options["--allowEmptyObjects"], "yes no")
1766
1767 MiscUtil.ValidateOptionTextValue("--BFactorChainCartoonPutty", Options["--BFactorChainCartoonPutty"], "yes no")
1768
1769 # Expand infiles to handle presence of multiple input files...
1770 InfileNames = MiscUtil.ExpandFileNames(Options["--infiles"], ",")
1771 if not len(InfileNames):
1772 MiscUtil.PrintError('No input files specified for "-i, --infiles" option')
1773
1774 # Validate file extensions...
1775 for Infile in InfileNames:
1776 MiscUtil.ValidateOptionFilePath("-i, --infiles", Infile)
1777 MiscUtil.ValidateOptionFileExt("-i, --infiles", Infile, "pdb cif")
1778 MiscUtil.ValidateOptionsDistinctFileNames("-i, --infiles", Infile, "-o, --outfile", Options["--outfile"])
1779 Options["--infileNames"] = InfileNames
1780
1781 MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "pml pse")
1782 MiscUtil.ValidateOptionsOutputFileOverwrite(
1783 "-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"]
1784 )
1785
1786 if re.match("^yes$", Options["--align"], re.I):
1787 if not re.match("^FirstInputFile$", Options["--alignRefFile"], re.I):
1788 AlignRefFile = Options["--alignRefFile"]
1789 MiscUtil.ValidateOptionFilePath("--alignRefFile", AlignRefFile)
1790 MiscUtil.ValidateOptionFileExt("--alignRefFile", AlignRefFile, "pdb cif")
1791 MiscUtil.ValidateOptionsDistinctFileNames(
1792 "--AlignRefFile", AlignRefFile, "-o, --outfile", Options["--outfile"]
1793 )
1794
1795 MiscUtil.ValidateOptionTextValue("--ignoreHydrogens", Options["--ignoreHydrogens"], "yes no")
1796
1797 MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
1798 MiscUtil.ValidateOptionIntegerValue("--labelFontID", Options["--labelFontID"], {})
1799
1800 MiscUtil.ValidateOptionFloatValue("--meshCarveRadius", Options["--meshCarveRadius"], {">": 0.0})
1801 MiscUtil.ValidateOptionTextValue("--meshComplex", Options["--meshComplex"], "yes no")
1802 MiscUtil.ValidateOptionTextValue("--meshChainComplex", Options["--meshChainComplex"], "yes no auto")
1803 MiscUtil.ValidateOptionFloatValue("--meshWidth", Options["--meshWidth"], {">": 0.0})
1804
1805 MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
1806
1807 MiscUtil.ValidateOptionFloatValue("--pocketContactsCutoff", Options["--pocketContactsCutoff"], {">": 0.0})
1808 MiscUtil.ValidateOptionFloatValue("--pocketDistanceCutoff", Options["--pocketDistanceCutoff"], {">": 0.0})
1809 if float(Options["--pocketContactsCutoff"]) > float(Options["--pocketDistanceCutoff"]):
1810 MiscUtil.PrintError(
1811 'The value, %s, specified using option "--pocketContactsCutoff" must be less than value, %s, specified using "-pocketDistanceCutoff" option.'
1812 % (Options["--pocketContactsCutoff"], Options["--pocketDistanceCutoff"])
1813 )
1814
1815 MiscUtil.ValidateOptionTextValue("--pocketSurface", Options["--pocketSurface"], "yes no")
1816
1817 MiscUtil.ValidateOptionTextValue("--surfaceComplex", Options["--surfaceComplex"], "yes no")
1818 MiscUtil.ValidateOptionTextValue("--surfaceChainComplex", Options["--surfaceChainComplex"], "yes no auto")
1819 MiscUtil.ValidateOptionFloatValue("--surfaceTransparency", Options["--surfaceTransparency"], {">=": 0.0, "<=": 1.0})
1820
1821 MiscUtil.ValidateOptionFloatValue("--volumeCarveRadius", Options["--volumeCarveRadius"], {">": 0.0})
1822 MiscUtil.ValidateOptionTextValue("--volumeComplex", Options["--volumeComplex"], "yes no")
1823 MiscUtil.ValidateOptionTextValue("--volumeChainComplex", Options["--volumeChainComplex"], "yes no auto")
1824
1825
1826 # Setup a usage string for docopt...
1827 _docoptUsage_ = """
1828 PyMOLVisualizeCryoEMDensity.py - Visualize cryo-EM density
1829
1830 Usage:
1831 PyMOLVisualizeCryoEMDensity.py [--align <yes or no>] [--alignMethod <align, cealign, super>]
1832 [--alignMode <FirstChain or Complex>] [--alignRefFile <filename>]
1833 [--allowEmptyObjects <yes or no>] [--BFactorChainCartoonPutty <yes or no>]
1834 [--BFactorColorPalette <text> ] [--chainIDs <First, All or ID1,ID2...>]
1835 [--densityMapFiles <file1,file2,file3,...>]
1836 [--ignoreHydrogens <yes or no>] [--ligandIDs <Largest, All or ID1,ID2...>] [--labelFontID <number>]
1837 [--meshCarveRadius <number>] [--meshComplex <yes or no>]
1838 [--meshChainComplex <yes, no, or auto>] [--meshColor <text>]
1839 [--meshLevel <number>] [--meshWidth <number>] [--PMLOut <yes or no>]
1840 [--pocketContactsLigandColor <text>] [--pocketContactsLigandHydrophobicColor <text>]
1841 [--pocketContactsSolventColor <text>] [--pocketContactsCutoff <number>]
1842 [--pocketContactsInorganicColor <text>] [--pocketDistanceCutoff <number>]
1843 [--pocketLabelColor <text>] [--pocketSurface <yes or no>]
1844 [--selectionsChain <ObjectName,SelectionSpec,...>] [--selectionsChainStyle <DisplayStyle>]
1845 [--surfaceComplex <yes or no>] [--surfaceChainComplex <yes, no or auto>]
1846 [--surfaceTransparency <number>] [--volumeCarveRadius <number>]
1847 [--volumeComplex <yes or no>] [--volumeChainComplex <yes, no, or auto>]
1848 [--volumeColorRamp <text>] [--overwrite] [-w <dir>] -i <infile1,infile2,...> -o <outfile>
1849 PyMOLVisualizeCryoEMDensity.py -h | --help | -e | --examples
1850
1851 Description:
1852 Generate PyMOL visualization files for viewing electron microscopy (EM) or
1853 cryo-EM density around chains, ligands, and ligand binding pockets in
1854 macromolecules including proteins and nucleic acids.
1855
1856 The supported input file formats are: Macromolecule - PDB (.pdb) or CIF(.cif),
1857 Cryo-EM Density - Collaborative Computational Project Number 4 (CCP4) ( .map)
1858
1859 The supported output file formats are: PyMOL script file (.pml), PyMOL session
1860 file (.pse)
1861
1862 The cryo-EM density and header files along with PDB files may be downloaded
1863 from appropriate servers using DownloadPDBFiles.pl script.
1864
1865 A variety of PyMOL groups and objects may be created for visualization of
1866 cryo-EM density present in map files. These groups and objects correspond to
1867 maps, volumes, meshes, surfaces,chains, ligands, inorganics, ligand binding
1868 pockets, polar interactions, and pocket hydrophobic surfaces. A complete
1869 hierarchy of all possible PyMOL groups and objects is shown below:
1870
1871 <PDBFileRoot>
1872 .Complex
1873 .Complex
1874 .CryoEM
1875 .Map
1876 .Volume
1877 .Mesh
1878 .Surface
1879 .Chain<ID>
1880 .Complex
1881 .Complex
1882 .CryoEM
1883 .Volume
1884 .Mesh
1885 .Surface
1886 .Chain
1887 .Chain
1888 .BFactor
1889 .Selections
1890 .<Name1>
1891 .Selection
1892 .CryoEM
1893 .Volume
1894 .Mesh
1895 .Surface
1896 .<Name2>
1897 ... ... ..
1898 .Solvent
1899 .Inorganic
1900 .Ligand<ID>
1901 .Ligand
1902 .Ligand
1903 .CryoEM
1904 .Volume
1905 .Mesh
1906 .Surface
1907 .Pocket
1908 .Pocket
1909 .CryoEM
1910 .Volume
1911 .Mesh
1912 .Surface
1913 .Polar_Contacts
1914 .Hydrophobic_Contacts
1915 .Surface
1916 .Pocket_Solvent
1917 .Pocket_Solvent
1918 .CryoEM
1919 .Volume
1920 .Mesh
1921 .Surface
1922 .Polar_Contacts
1923 .Pocket_Inorganic
1924 .Pocket_Inorganic
1925 .CryoEM
1926 .Volume
1927 .Mesh
1928 .Surface
1929 .Polar_Contacts
1930 .Ligand<ID>
1931 .Ligand
1932 ... ... ...
1933 .Pocket
1934 ... ... ...
1935 .Pocket_Solvent
1936 ... ... ...
1937 .Pocket_Inorganic
1938 ... ... ...
1939 .Chain<ID>
1940 ... ... ...
1941 .Ligand<ID>
1942 ... ... ...
1943 .Ligand<ID>
1944 ... ... ...
1945 .Chain<ID>
1946 ... ... ...
1947 <PDBFileRoot>
1948 .Complex
1949 ... ... ...
1950 .Chain<ID>
1951 ... ... ...
1952 .Ligand<ID>
1953 ... ... ...
1954 .Ligand<ID>
1955 ... ... ...
1956 .Chain<ID>
1957 ... ... ...
1958
1959 The meshes, volumes, and surfaces are not created for complete complex in input
1960 files by default. A word to the wise: The creation of these mesh, volume, and surface
1961 objects may slow down loading of PML file and generation of PSE file, based on the
1962 size of input complex and map files. The generation of PSE file may also fail. In
1963 addition, you may want to interactively manipulate the contour level for meshes,
1964 volumes, and surfaces. The recommended value for contour level is automatically
1965 retrieved from header files available from EM density server. The recommended
1966 value may not always work.
1967
1968 Options:
1969 -a, --align <yes or no> [default: no]
1970 Align input files to a reference file before visualization along with
1971 available cryo-EM density map files.
1972 --alignMethod <align, cealign, super> [default: super]
1973 Alignment methodology to use for aligning input files to a reference
1974 file.
1975 --alignMode <FirstChain or Complex> [default: FirstChain]
1976 Portion of input and reference files to use for spatial alignment of
1977 input files against reference file. Possible values: FirstChain or
1978 Complex.
1979
1980 The FirstChain mode allows alignment of the first chain in each input
1981 file to the first chain in the reference file along with moving the rest
1982 of the complex to coordinate space of the reference file. The complete
1983 complex in each input file is aligned to the complete complex in reference
1984 file for the Complex mode.
1985 --alignRefFile <filename> [default: FirstInputFile]
1986 Reference input file name. The default is to use the first input file
1987 name specified using '-i, --infiles' option.
1988 --allowEmptyObjects <yes or no> [default: no]
1989 Allow creation of empty PyMOL objects corresponding to solvent and
1990 inorganic atom selections across chains, ligands, and ligand binding pockets
1991 in input file(s).
1992 -b, --BFactorChainCartoonPutty <yes or no> [default: yes]
1993 A cartoon putty around individual chains colored by B factors. The minimum
1994 and maximum values for B factors are automatically detected. These values
1995 indicate spread of cryo-EM density around atoms. The 'blue_white_red' color
1996 palette is deployed for coloring the cartoon putty.
1997 --BFactorColorPalette <text> [default: blue_white_red]
1998 Color palette for coloring cartoon putty around chains generated using B
1999 factors. Any valid PyMOL color palette name is allowed. No validation is
2000 performed. The complete list of valid color palette names is a available
2001 at: pymolwiki.org/index.php/Spectrum. Examples: blue_white_red,
2002 blue_white_magenta, blue_red, green_white_red, green_red.
2003 -c, --chainIDs <First, All or ID1,ID2...> [default: First]
2004 List of chain IDs to use for visualizing cryo-EM density. Possible values:
2005 First, All, or a comma delimited list of chain IDs. The default is to use the
2006 chain ID for the first chain in each input file.
2007 -d, --densityMapFiles <file1,file2,file3,...> [default: auto]
2008 CryoEM density map file names. The EMDB ID is retrieved from PDB and CIF
2009 file to set the cryo-EM density file name during automatic detection of
2010 density files. The format of the file name is as follows:
2011
2012 emd_<EMDBID>.map.gz or emd_<EMDBID>.map
2013
2014 The density files must be present in the working directory.
2015 -e, --examples
2016 Print examples.
2017 -h, --help
2018 Print this help message.
2019 -i, --infiles <infile1,infile2,infile3...>
2020 Input file names.
2021 --ignoreHydrogens <yes or no> [default: yes]
2022 Ignore hydrogens for ligand and pocket views.
2023 -l, --ligandIDs <Largest, All or ID1,ID2...> [default: Largest]
2024 List of ligand IDs present in chains for visualizing cryo-EM density across
2025 ligands and ligand binding pockets. Possible values: Largest, All, or a comma
2026 delimited list of ligand IDs. The default is to use the largest ligand present
2027 in all or specified chains in each input file.
2028
2029 Ligands are identified using organic selection operator available in PyMOL.
2030 It'll also identify buffer molecules as ligands. The largest ligand contains
2031 the highest number of heavy atoms.
2032 --labelFontID <number> [default: 7]
2033 Font ID for drawing labels. Default: 7 (Sans Bold). Valid values: 5 to 16.
2034 The specified value must be a valid PyMOL font ID. No validation is
2035 performed. The complete lists of valid font IDs is available at:
2036 pymolwiki.org/index.php/Label_font_id. Examples: 5 - Sans;
2037 7 - Sans Bold; 9 - Serif; 10 - Serif Bold.
2038 --meshCarveRadius <number> [default: 1.6]
2039 Radius in Angstroms around atoms for including cryo-EM density.
2040 --meshComplex <yes or no> [default: no]
2041 Create meshes for complete complex in each input file using corresponding
2042 density map file.
2043 --meshChainComplex <yes, no, or auto> [default: auto]
2044 Create meshes for individual chain complex in each input file using
2045 corresponding density map file. By default, the meshes are automatically
2046 created for chain complexes without any ligands.
2047 --meshColor <text> [default: blue]
2048 Line color for meshes corresponding to density maps.. The specified value
2049 must be valid color. No validation is performed.
2050 --meshLevel <number1,number2,...> [default: auto]
2051 Comma delimited list of contour levels in sigma units for generating meshes
2052 for each input file using corresponding density map file. The default is to
2053 automatically retrieve the recommended contour levels for each input
2054 file. The header file emd-<EMDBID>.xml corresponding to an input file
2055 must be present in the working directory to automatically retrieve
2056 recommended value for mesh contour level. Otherwise, the default contour
2057 level is set to 1.
2058
2059 You may want to interactively manipulate the contour level for meshes and
2060 surfaces. The default recommended value may not always work.
2061 --meshWidth <number> [default: 0.5]
2062 Line width for mesh lines corresponding to density maps.
2063 -o, --outfile <outfile>
2064 Output file name.
2065 -p, --PMLOut <yes or no> [default: yes]
2066 Save PML file during generation of PSE file.
2067 --pocketContactsLigandColor <text> [default: orange]
2068 Color for drawing polar contacts between ligand and pocket residues.
2069 The specified value must be valid color. No validation is performed.
2070 --pocketContactsLigandHydrophobicColor <text> [default: purpleblue]
2071 Color for drawing hydrophobic contacts between ligand and pocket residues.
2072 The specified value must be valid color. No validation is performed. The
2073 hydrophobic contacts are shown between pairs of carbon atoms not
2074 connected to hydrogen bond donor or acceptors atoms as identified
2075 by PyMOL.
2076 --pocketContactsSolventColor <text> [default: marine]
2077 Color for drawing polar contacts between solvent and pocket residues.
2078 The specified value must be valid color. No validation is performed.
2079 --pocketContactsInorganicColor <text> [default: deepsalmon]
2080 Color for drawing polar contacts between inorganic and pocket residues.
2081 The specified value must be valid color. No validation is performed.
2082 --pocketContactsCutoff <number> [default: 4.0]
2083 Distance in Angstroms for identifying polar and hyrdophobic contacts
2084 between atoms in pocket residues and ligands.
2085 --pocketDistanceCutoff <number> [default: 5.0]
2086 Distance in Angstroms for identifying pocket residues around ligands.
2087 --pocketLabelColor <text> [default: magenta]
2088 Color for drawing residue or atom level labels for a pocket. The specified
2089 value must be valid color. No validation is performed.
2090 --pocketSurface <yes or no> [default: yes]
2091 Hydrophobic surface around pocket. The pocket surface is colored by
2092 hydrophobicity. It is only valid for proteins. The color of amino acids is
2093 set using the Eisenberg hydrophobicity scale. The color varies from red
2094 to white, red being the most hydrophobic amino acid.
2095 --selectionsChain <ObjectName,SelectionSpec,...> [default: None]
2096 Custom selections for chains. It is a pairwise list of comma delimited values
2097 corresponding to PyMOL object names and selection specifications. The
2098 selection specification must be a valid PyMOL specification. No validation is
2099 performed.
2100
2101 The PyMOL objects are created for each chain corresponding to the
2102 specified selections. The display style for PyMOL objects is set using
2103 value of '--selectionsChainStyle' option.
2104
2105 The specified selection specification is automatically appended to appropriate
2106 chain specification before creating PyMOL objects.
2107
2108 For example, the following specification for '--selectionsChain' option will
2109 generate PyMOL objects for chains containing Cysteines and Serines:
2110
2111 Cysteines,resn CYS,Serines,resn SER
2112
2113 --selectionsChainStyle <DisplayStyle> [default: sticks]
2114 Display style for PyMOL objects created for '--selectionsChain' option. It
2115 must be a valid PyMOL display style. No validation is performed.
2116 --surfaceComplex <yes or no> [default: no]
2117 Create surfaces for complete complex in input file(s) corresponding to density
2118 map.
2119 --surfaceChainComplex <yes, no or auto> [default: auto]
2120 Create surfaces for individual chain complexes in each input file using corresponding
2121 density map file. By default, the surfaces are automatically created for chain complexes
2122 without any ligands.
2123 --surfaceTransparency <number> [default: 0.25]
2124 Surface transparency for molecular and cryo-EM density surfaces.
2125 --overwrite
2126 Overwrite existing files.
2127 --volumeCarveRadius <number> [default: 1.6]
2128 Radius in Angstroms around atoms for including cryo-EM density.
2129 --volumeComplex <yes or no> [default: no]
2130 Create volumes for complete complex in each input file using corresponding density
2131 map file.
2132 --volumeChainComplex <yes, no, or auto> [default: auto]
2133 Create volumes for individual chain complex in each input file using corresponding
2134 density map file. By default, the volumes are automatically created for chain
2135 complexes without any ligands.
2136 --volumeColorRamp <text> [default: auto]
2137 Name of a volume color ramp for density map files. The specified value must
2138 be a valid name. No validation is performed. The following volume color ramps
2139 are currently available in PyMOL: default, 2fofc, fofc, rainbow, and rainbow2.
2140
2141 The default is to automatically create a new volume color ramp for the first
2142 input file using recommended contour level with an offset of 0.3 around this value.
2143 The header file emd-<EMDBID>.xml must be present in the working directory to
2144 automatically retrieve recommended contour level and generate a volume color ramp.
2145 Otherwise, PyMOL default volume color ramp is employed to color volumes.
2146
2147 The volume color ramp automatically created for the first input file is used for all
2148 other input files.
2149 -w, --workingdir <dir>
2150 Location of working directory which defaults to the current directory.
2151
2152 Examples:
2153 To download structure and cryo-EM data for 5K12, 5UMD, 5W81, and 5UAK
2154 before running the following examples, type:
2155
2156 % DownloadPDBFiles.pl --DensityMap yes 5K12,5UMD,5W81,5UAK
2157
2158 To visualize cryo-EM density at recommended contour level for the first
2159 chain complex in a PDB file using corresponding density map and header
2160 file, and generate a PML file type:
2161
2162 % PyMOLVisualizeCryoEMDensity.py -i 5K12.pdb -o 5K12.pml
2163
2164 To visualize cryo-EM density at recommended contour level for the first
2165 chain complex in a PDB file and highlighting densities for all cysteines and
2166 serines using corresponding density map and header file, and generate
2167 a PML file type:
2168
2169 % PyMOLVisualizeCryoEMDensity.py -i 5K12.pdb -o 5K12.pml
2170 --selectionsChain "Csysteines,resn cys,Serines,resn ser"
2171
2172 To visualize electron density for the largest ligand in chain K, and ligand
2173 binding pocket to highlight ligand interactions with pockect residues,
2174 solvents and inorganics, in a PDB and using corresponding map files, and
2175 generate a PML file, type:
2176
2177 % PyMOLVisualizeCryoEMDensity.py -c K -i 5UMD.cif -o 5UMD.pml
2178
2179 To visualize cryo-EM density for all chains along with any solvents in a
2180 PDB file and using corresponding map files, and generate a PML file, type:
2181
2182 % PyMOLVisualizeCryoEMDensity.py -c all -i 5K12.pdb -o 5K12.pml
2183
2184 To visualize cryo-EM density at a specific contour level for the first chain
2185 complex along with volume and surface in a PDB file using corresponding
2186 to a specific density map file, and generate a PML file, type:
2187
2188 % PyMOLVisualizeCryoEMDensity.py -d emd_8194.map.gz --meshLevel 1.0
2189 --surfaceChainComplex yes --volumeChainComplex yes -i 5K12.pdb
2190 -o 5K12.pml
2191
2192 To align and visualize cryo-EM density at recommended contour levels for the
2193 largest ligand in the first chain along with pockets or the first chain complex
2194 in input files using corresponding maps and header files, type:
2195
2196 % PyMOLVisualizeCryoEMDensity.py -a yes -i "5W81.pdb,5UAK.pdb"
2197 -o SampleOut.pml
2198
2199 To align and visualize cryo-EM density at recommended contour levels for all
2200 chains and ligands in input files using specified density files, type:
2201 in input files using corresponding maps and header files, type:
2202
2203 % PyMOLVisualizeCryoEMDensity.py -a yes -i "5W81.pdb,5UAK.pdb"
2204 -o SampleOut.pml -c all -l all -d "emd_8782.map.gz,emd_8516.map.gz"
2205
2206 Author:
2207 Manish Sud(msud@san.rr.com)
2208
2209 See also:
2210 DownloadPDBFiles.pl, PyMOLVisualizeCavities.py,
2211 PyMOLVisualizeElectronDensity.py, PyMOLVisualizeInterfaces.py,
2212 PyMOLVisualizeMacromolecules.py, PyMOLVisualizeSurfaceAndBuriedResidues.py
2213
2214 Copyright:
2215 Copyright (C) 2025 Manish Sud. All rights reserved.
2216
2217 The functionality available in this script is implemented using PyMOL, a
2218 molecular visualization system on an open source foundation originally
2219 developed by Warren DeLano.
2220
2221 This file is part of MayaChemTools.
2222
2223 MayaChemTools is free software; you can redistribute it and/or modify it under
2224 the terms of the GNU Lesser General Public License as published by the Free
2225 Software Foundation; either version 3 of the License, or (at your option) any
2226 later version.
2227
2228 """
2229
2230 if __name__ == "__main__":
2231 main()