0

I am working in python and i want to get a series of 3D images for the molecules I'm using.

I have .mol files stored in my folder and for each of them I would like to obtain a 3D render of its 'stick' representation. With py3Dmol i can get a 3D structure of the molecule, but i can only view it and it is not stored anywhere in python. Here a source (from the author of the package) explaining why images cannot be saved

Do you have any suggestion on how to do automatize the creation of 3D structure images for a set of molecule?

Mirk
  • 43
  • 4
  • Use pymol to load your mol pymol.cmd.load( filename.mol , str(filename) , manipulate it and use cmd.png( .... ) to save it as png dont forget to use the ray parameter to make it look nice. A for loop on your molecule folder should be enough. You could rotate the molecule to save different views of it. I guess in any case you'll have to inspect them one by one the get the right projection though. – pippo1980 Jul 16 '23 at 15:55

2 Answers2

1

OK , here my attempt, please have a look at Multiple PyMOL Instances in Python Script and Launching From a Script that explains how this works:

"""
Yes it's possible to have independent instances. The API has actually been 
around for a long time. For some reason it was never widely adopted and thus is 
not very thoroughly tested. Please report any bugs you encounter.

Example:
"""
import pymol2
p = pymol2.PyMOL()
p.start()
p.cmd.fragment('ala')
p.cmd.show_as('sticks')
p.cmd.zoom()
p.cmd.png('/tmp/ala.png', 1000, 800, dpi=150, ray=1)
p.stop()

Code :

import pymol2

import os

work_dir = "." 

file_folders = os.listdir(work_dir)  


mol_files = [item for item in file_folders if os.path.isfile(item) and   item.rsplit('.')[1] == 'mol']

print(mol_files)


for mol_file in mol_files:
    

    p = pymol2.PyMOL()
    
    p.start()
    
    mol_name = mol_file.rsplit('.')[0]
    
    print(mol_file.rsplit('.')[0])
    
    try :
     
        p.cmd.load(mol_file , mol_name)
    
        p.cmd.hide(representation = 'sticks' , selection = mol_name)
        
        p.cmd.show(representation = 'lines' , selection = mol_name)
        
        p.cmd.do('set ray_opaque_background, 0')
        ## or to get black background instead of transparent
        #p.cmd.bg_color(color="black")
        #p.cmd.do('set ray_opaque_background, 1')
        
        p.cmd.orient(mol_name)
        
        p.cmd.png(mol_name+'.png' , dpi = 400, width = 5000, ray = 1)
        
        p.cmd.remove(mol_name)
        
        p.stop()
        
    except :
        
        print('\nError ----> something is wrong with ', mol_name+'.mol file \n')
    
print('finished ...............................')

Note that the molecules are oriented on the screen by pymol.cm.orient() that as per the wiki:

orient aligns the principal components of the atoms in the selection with the XYZ axes. T

AS an example here the pic for GLC from Chemical Components in the PDB GLC : Summary

pic

pippo1980
  • 2,181
  • 3
  • 14
  • 30
0

I think You can use the Python PIL library to capture the Py3Dmol view as an image.

May be try this

from rdkit import Chem
from rdkit.Chem import AllChem
import py3Dmol
from PIL import Image
import os

def read_mol_from_file(file_path):
    mol = Chem.MolFromMolFile(file_path)
    return mol

def generate_3D_coordinates(mol):
    AllChem.EmbedMolecule(mol, randomSeed=42)

def render_to_png(mol, filename):
    block = Chem.MolToMolBlock(mol)
    viewer = py3Dmol.view(width=300, height=300)
    viewer.addModel(block, "sdf")
    viewer.setStyle({'stick': {}})
    viewer.zoomTo()
    viewer.show()
    # Capture the view as an image (this part needs manual intervention)
    # An automated screenshot capturing method can be used here

# Directory containing your .mol files
mol_dir = "./molecules"

for mol_file in os.listdir(mol_dir):
    if mol_file.endswith('.mol'):
        mol_path = os.path.join(mol_dir, mol_file)
        mol = read_mol_from_file(mol_path)
        
        if not mol.GetNumConformers():  # Check if 3D coordinates exist
            generate_3D_coordinates(mol)
        
        output_file = f"{mol_file.split('.')[0]}.png"
        render_to_png(mol, output_file)
user4959
  • 455
  • 1
  • 5
  • 8