3. Хемоинформатика¶

In [14]:
from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit import RDConfig
from rdkit.Chem.Draw import IPythonConsole 
from rdkit.Chem import Draw
import numpy as np
from IPython.display import display,Image

Изобразим ибупрофен.

In [15]:
ibu=Chem.MolFromSmiles('CC(C)CC1=CC=C(C=C1)C(C)C(=O)O')
AllChem.Compute2DCoords(ibu)
display(ibu)
No description has been provided for this image
In [16]:
import rdkit.Chem.Lipinski as Lipinksy
print(Lipinksy.NumHDonors(ibu))
print(Lipinksy.NumHAcceptors(ibu))
print(Lipinksy.rdMolDescriptors.CalcExactMolWt(ibu))
print(Lipinksy.rdMolDescriptors.CalcCrippenDescriptors(ibu)[0])
1
1
206.130679816
3.073200000000001

Вспомним параметры для правила Лепински: соединение, чтобы быть похожим на лекарство, должно:

• Иметь менее 5 атомов-доноров водородной связи;

• Обладать молекулярным весом менее 500;

• Иметь липофильность (log P — коэффициент распределения вещества на границе раздела вода-октанол) менее 5;

• Иметь суммарно не более 10 атомов азота и кислорода (грубая оценка количества акцепторов водородной связи)

Теперь модифицируем ибупрофен так, чтобы к нему можно было присоединить азид, то есть сделаем ему концевую алкильную группу. А также рассмотрим то, что должно аолучиться в результате клик-реакции.

In [17]:
ibuin=Chem.MolFromSmiles('CC(C#C)CC1=CC=C(C=C1)C(C)C(=O)O')
AllChem.Compute2DCoords(ibuin)
display(ibuin)
No description has been provided for this image
In [18]:
ibuzid=Chem.MolFromSmiles('N1C=C(N=N1)C(C)CC1=CC=C(C=C1)C(C)C(=O)O')
AllChem.Compute2DCoords(ibuzid)
display(ibuzid)
No description has been provided for this image

Скачаем как можно больше различных азидов.

In [28]:
import pubchempy as pcp

compounds = []
per_page = 1000
for smiles in ["N=[N+]=[N-]", "N=N=N", "NN#N"]:
    for i in range(5):
        try:
            a = pcp.get_properties(properties="CanonicalSMILES", identifier=smiles, namespace="smiles", searchtype="substructure", RingsNotEmbedded=True, listkey_count=per_page, listkey_start=i*per_page)
        except:
            print ('oh')
        print ("Retrieved page {} of {} search".format(i+1, smiles))
        compounds.extend(a)
Retrieved page 1 of N=[N+]=[N-] search
Retrieved page 2 of N=[N+]=[N-] search
Retrieved page 3 of N=[N+]=[N-] search
Retrieved page 4 of N=[N+]=[N-] search
Retrieved page 5 of N=[N+]=[N-] search
Retrieved page 1 of N=N=N search
Retrieved page 2 of N=N=N search
Retrieved page 3 of N=N=N search
Retrieved page 4 of N=N=N search
Retrieved page 5 of N=N=N search
Retrieved page 1 of NN#N search
Retrieved page 2 of NN#N search
Retrieved page 3 of NN#N search
Retrieved page 4 of NN#N search
Retrieved page 5 of NN#N search
In [29]:
smiles_list = [x["CanonicalSMILES"] for x in compounds]
print(len(smiles_list))
smiles_list = list(filter(lambda x: len(x) < 30 and not '.' in x,
                          smiles_list))
print(len(smiles_list))
15000
315
In [35]:
from random import shuffle, seed

groups = ['N=[N+]=[N-]', '[N-]=[N+]=[N-]', '[N-][N+]#[N]', '[N]#[N+][N-]', '[N-][N]#[N+]', '[N+]#[N][N-]']
template = 'N1C=C(N=N1)C(C)CC1=CC=C(C=C1)C(C)C(=O)O'

result = []
num_to_check = 2000

# Новую молекулу лучше создавать в try из-за битых Smiles
#При первом запуске ячейки убрать решетки, чтобы перемешать
#shuffle(smiles_list)
for smi in smiles_list[:num_to_check]:
    for group in groups:
        if group in smi:
            newsmi = smi.replace(group, template)
            break
    else:
        continue
# Если новая молекула удолтворяет правилу пяти, сохраним в массив и покажем
    try:
        new_mol=Chem.MolFromSmiles(newsmi)
        if (Lipinksy.NumHDonors(new_mol) <= 5 and 
            Lipinksy.NumHAcceptors(new_mol) <= 10 and 
            Lipinksy.rdMolDescriptors.CalcExactMolWt(new_mol) <=500 and 
            Lipinksy.rdMolDescriptors.CalcCrippenDescriptors(new_mol)[0] <= 5):
                result.append((new_mol, Lipinksy.rdMolDescriptors.CalcCrippenDescriptors(new_mol)[0]))
    except Exception:
        continue

print(len(result))

result.sort(key=lambda x: x[1])
mols = [x[0] for x in result]
140

Посмотрим на топ-12 гидрофильных молекул. Вот они:

In [36]:
Draw.MolsToGridImage(mols[:12],useSVG=True, molsPerRow=3, subImgSize=(400, 320))
Out[36]:
No description has been provided for this image

Посмотрим на 5-го представителя из наиболее гидрофильных молекул.

In [37]:
from rdkit.Chem.Draw import SimilarityMaps
somemol = mols[4]
SimilarityMaps.GetMorganFingerprint(somemol, fpType='bv')
SimilarityMaps.GetSimilarityMapForFingerprint(ibu,
                    somemol, SimilarityMaps.GetMorganFingerprint)
Out[37]:
(<Figure size 250x250 with 1 Axes>, 0.19272727272727275)
No description has been provided for this image

В самом деле, остаток ибупрофена очень похож на ибупрофен, а присоединенный азид не похож.

Теперь получим 3D структуру этой молекулы и покрутим ее.

In [38]:
m3d=Chem.AddHs(somemol)
Chem.AllChem.EmbedMolecule(m3d)
AllChem.MMFFOptimizeMolecule(m3d,maxIters=500,nonBondedThresh=200 )
Out[38]:
0
In [43]:
import nglview as nv
nv.show_rdkit(m3d)
NGLWidget()

К сожалению, модуль выдает ошибку при импорте, из-за чего покрутить модель в html невозможно.

Поэтому просто отобразим снимок этой молекулы.

In [44]:
display(m3d)
No description has been provided for this image