ribesstefano's picture
Setup the spaces app
9dd777e
import re
import numpy as np
from rdkit import Chem, DataStructs
from rdkit.Chem import (
AllChem,
Draw,
rdFMCS,
rdMolAlign,
)
def save_as_svg(svg_content, filename, num_mols):
"""Save SVG content to a file."""
with open(filename, 'w') as file:
data = str(svg_content.data)
data = data.replace('1500', str(500*num_mols))
file.write(data)
def align_molecules_2D(ref_mol, to_align_mol):
AllChem.Compute2DCoords(ref_mol)
AllChem.Compute2DCoords(to_align_mol)
# Find the maximum common substructure and use it to align molecules
mcs = rdFMCS.FindMCS([ref_mol, to_align_mol])
mcs_mol = Chem.MolFromSmarts(mcs.smartsString)
ref_match = ref_mol.GetSubstructMatch(mcs_mol)
align_match = to_align_mol.GetSubstructMatch(mcs_mol)
atom_map = list(zip(align_match, ref_match))
rdMolAlign.AlignMol(to_align_mol, ref_mol, atomMap=atom_map)
return to_align_mol
def align_molecules_by_coordinates(ref_mol, to_align_mol):
# Find the maximum common substructure
AllChem.Compute2DCoords(to_align_mol)
mcs = rdFMCS.FindMCS([ref_mol, to_align_mol])
mcs_mol = Chem.MolFromSmarts(mcs.smartsString)
ref_match = ref_mol.GetSubstructMatch(mcs_mol)
align_match = to_align_mol.GetSubstructMatch(mcs_mol)
# Copy the coordinates from the reference molecule to the molecule to be aligned
ref_conf = ref_mol.GetConformer()
align_conf = to_align_mol.GetConformer()
for ref_idx, align_idx in zip(ref_match, align_match):
ref_pos = ref_conf.GetAtomPosition(ref_idx)
align_conf.SetAtomPosition(align_idx, ref_pos)
return to_align_mol
def draw_molecule_to_svg(mol, size=(500, 500), scale=1.0):
drawer = Draw.rdMolDraw2D.MolDraw2DSVG(size[0], size[1])
drawer.drawOptions().fixedBondLength = scale
drawer.DrawMolecule(mol)
drawer.FinishDrawing()
svg = drawer.GetDrawingText()
svg = re.sub(r'\<\?xml.*?\?\>', '', svg) # Remove XML declaration
svg = svg.replace('<svg', '<g').replace(
'</svg>', '</g>') # Replace svg tags with g tags
return svg
def combine_svgs(svgs, output_filename, dimensions=None, size=(500, 500), xy_shifts=None):
if dimensions is None:
dimensions = (len(svgs), 1)
if xy_shifts is None:
xy_shifts = [(0, 0) for i in range(dimensions[0]*dimensions[1])]
width, height = size
grid_width, grid_height = dimensions
# Include only one XML declaration and the opening <svg> tag
combined_svg = f'<?xml version="1.0" standalone="no"?>\n'
combined_svg += f'<svg width="{grid_width * width}px" height="{grid_height * height}px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n'
# Arrange SVGs in a grid
for i, (svg, xy_shift) in enumerate(zip(svgs, xy_shifts)):
x = (i % grid_width) * width
y = (i // grid_width) * height
combined_svg += f'<g transform="translate({x+xy_shift[0]},{y-xy_shift[1]})">{svg}</g>\n'
combined_svg += '</svg>'
with open(output_filename, 'w') as file:
file.write(combined_svg)
def draw_molecule_with_highlighted_bonds(mol, bonds_to_highlight):
"""
Draws a molecule with specified atoms and bonds highlighted.
Parameters:
- smiles (str): SMILES string for the molecule.
- atoms_to_highlight (set): Set of atom indices to highlight.
- bonds_to_highlight (list): List of bond indices to highlight.
- highlight_bond_colors (dict): Dictionary mapping bond indices to colors.
"""
# Create molecule from SMILES
# Initialize drawer
d2d = Draw.rdMolDraw2D.MolDraw2DSVG(350*2, 300*2)
# Set drawing options
d2d.drawOptions().useBWAtomPalette()
d2d.drawOptions().continuousHighlight = False
d2d.drawOptions().highlightBondWidthMultiplier = 24
d2d.drawOptions().setHighlightColour((0, 0, 1))
d2d.drawOptions().fillHighlights = False
# Draw the molecule with highlights
d2d.DrawMolecule(mol,
highlightAtoms=[],
highlightBonds=bonds_to_highlight)
d2d.FinishDrawing()
# Convert drawing to image and display
svg = d2d.GetDrawingText()
svg = svg.replace('svg:', '')
return svg
def align_mol_2D_ver2(template, query):
mcs = rdFMCS.FindMCS([template, query])
patt = Chem.MolFromSmarts(mcs.smartsString)
query_match = query.GetSubstructMatch(patt)
template_match = template.GetSubstructMatch(patt)
rms = AllChem.AlignMol(query, template, atomMap=list(
zip(query_match, template_match)))
return template, query
def transform_molecule(mol, degrees, translate_x=0, translate_y=0, flip_x_axis=False):
"""Apply rotation, translation, and optionally flip the molecule."""
radians = np.deg2rad(degrees)
rotation_matrix = np.array([
[np.cos(radians), -np.sin(radians), 0],
[np.sin(radians), np.cos(radians), 0],
[0, 0, 1]
])
AllChem.Compute2DCoords(mol)
conf = mol.GetConformer()
for i in range(conf.GetNumAtoms()):
pos = np.array(conf.GetAtomPosition(i))
new_pos = np.dot(rotation_matrix, pos)
new_pos[0] += translate_x # Translate along the x-axis
new_pos[1] += translate_y # Translate along the y-axis
if flip_x_axis:
new_pos[1] = -new_pos[1] # Flip along the x-axis
conf.SetAtomPosition(i, new_pos)
def tailored_framework_example(mol_ms):
# remove lone atoms
# define all atoms to be atom number 1
# define all bonds to be single bonds
mol_ms_w = Chem.RWMol(mol_ms)
atom_idx_to_remove = []
for atom in mol_ms_w.GetAtoms():
# lone atom. Need to remove it to create the generic framework.
if atom.GetDegree() == 1:
atom_idx_to_remove.append(atom.GetIdx())
continue
atom.SetAtomicNum(0)
for bond in mol_ms_w.GetBonds():
bond.SetBondType(Chem.rdchem.BondType.SINGLE)
atom_idx_to_remove.sort(reverse=True)
for atom_idx in atom_idx_to_remove:
mol_ms_w.RemoveAtom(atom_idx)
mol_ms_new = mol_ms_w.GetMol()
return mol_ms_new