Учебный сайт

Бредихина Данилы

  • VIII
  • Работа с PyMol

Запустим PyMol для работы в режиме сервера.

In [1]:
import time
from xmlrpclib import ServerProxy
from IPython.display import Image
cmd = ServerProxy(uri="http://localhost:9123/RPC2")

defaultImage = '/tmp/pymolimg.png'
def prepareImage(width=300, height=300, sleep=2, filename=defaultImage):
    ## To save the rendered image
    cmd.ray(width, height)
    cmd.png('/tmp/pymolimg.png')
    time.sleep(sleep)

# Define some shortcuts
def focus(x):
    cmd.center(x)
    cmd.zoom(x)

Мутация в структуре белка

Загрузим структуру лизоцима радужной форели в комплексе с сахарами (PDB ID 1LMP).

In [2]:
cmd.fetch('1lmp')
cmd.hide('nonbonded')
cmd.bg_color('white')

cmd.select('ligand', '1lmp and resn nag+ndg')
cmd.disable('ligand')
cmd.show('sticks', 'ligand')

prepareImage()
Image(defaultImage)
Out[2]:

Выберем остаток, например, аспартат 52.

In [3]:
mutant_resi = 'resi 52'

focus(mutant_resi)
cmd.select(mutant_resi)
prepareImage()
Image(defaultImage)
Out[3]:

Проведём мутацию, заменив этот остаток, например, на аланин.

In [4]:
# Mutate Asp to Ala
cmd.wizard("mutagenesis")
cmd.do("refresh_wizard")
cmd.do('cmd.get_wizard().do_select("%s")' % mutant_resi)
cmd.do('cmd.get_wizard().set_mode("ALA")')
cmd.do("refresh_wizard")
cmd.do("cmd.get_wizard().apply()")
cmd.do("cmd.set_wizard()")

# Sometimes the temp mutant is not removed
try:
    cmd.remove("/_tmp_mut")
except:
    pass

prepareImage()
Image(defaultImage)
Out[4]:

Создание анимации

Загрузим немутированный белок как новый объект. Покрасим каждую структуру в свой цвет, выделив при этом отдельными цветами остаток с номером 63 и сахар. Перед началом анимации сместим немутированный белок влево.

In [5]:
cmd.fetch('1lmp', 'original')
cmd.hide('everything')
cmd.select('ligand1', '1lmp and resn nag+ndg')
cmd.select('ligand2', 'original and resn nag+ndg')
cmd.disable('ligand*')

cmd.set('cartoon_side_chain_helper', 'on')

cmd.show('cartoon', '(1lmp | original) & !ligand*')
cmd.colour('black', '1lmp')
cmd.colour('density', 'original')

cmd.show('sticks', 'ligand*')
cmd.colour('smudge', 'ligand*')

cmd.show('sticks', mutant_resi)
cmd.colour('red', '1lmp & '+mutant_resi)
cmd.colour('yellow', 'original & '+mutant_resi)

cmd.translate('[-50, 0, 0]', 'original')
focus('1lmp + original')

prepareImage(500, 500)
Image(defaultImage)
Out[5]:

В начале анимации совместим белки. Затем увеличим место мутации.

In [6]:
#cmd.colour('black', 'original and not %s' % mutant_resi)
near_mutant = 'byres( %s extend 3)' % mutant_resi
cmd.hide('everything', near_mutant)
cmd.show('lines', near_mutant)
cmd.show('sticks', '%s & !original' % mutant_resi)

cmd.mset('1 x360')
cmd.frame('1')
cmd.clip('near', '100'); cmd.clip('far', '-100')
cmd.mview('store')
cmd.do('mview store, object=original')

# Align the proteins
cmd.frame('60')
cmd.do('translate [50, 0, 0], object=original')
cmd.do('mview store, object=original')

# This step might help to deal with auto-interpolation
cmd.frame('360')
cmd.do('mview store, object=original')

# Close-up of the proteins aligned
cmd.frame('120')
focus('original')
cmd.mview('store')

# Close-up of the mutated residues
cmd.frame('180')
cmd.do('mview store, object=original')
focus(mutant_resi)
cmd.do('util.mrock(180, 360, 360)')
cmd.mview('store')

cmd.frame('360')
focus(mutant_resi)
cmd.clip('near', '100'); cmd.clip('far', '-100')
cmd.mview('store')

cmd.do('mview interpolate, object=original')
cmd.mview('reinterpolate')

# cmd.mplay()  # may be used to play the movie

## Saving the frames
cmd.set('ray_trace_frames', '1')
cmd.set('ray_trace_mode', '1')
cmd.set('antialias', '1')
cmd.mpng('1LMP_mutation')

Чтобы из получившихся трёхсот шестидесяти изображений сделать фильм, воспользуемся программой ffmpeg.

ffmpeg -i 1LMP_mutation0%03d.png -c:v libx264 -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" movie_1lmp.mp4

In [8]:
from IPython.display import HTML
from base64 import b64encode
video = open('movie_1lmp.mp4', 'rb').read()
video_encoded = b64encode(video)
video_tag = '<video controls alt="PyMol Movie" src="data:video/mp4;base64,{0}" type="video/mp4">'.format(video_encoded)
HTML(data=video_tag)
Out[8]:

Добавление метки к белку

Присоединим к белку флуорусцентную метку TAMRA. Для этого сначала загрузим её структуру в формате .SDF.

In [9]:
import urllib2
tamra_url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/2762604/record/SDF/?response_type=save&record_type=3d"
connection = urllib2.urlopen(tamra_url)
sdf = connection.read()
with open('tamra.sdf', 'w') as w:
    w.write(sdf)

Теперь загрузим файл в PyMol.

In [15]:
cmd.load('tamra.sdf')

# Make some visual changes
cmd.zoom('original')
cmd.disable('1lmp')
cmd.colour('deepblue', 'original & '+mutant_resi)
# Clear animation frames
cmd.mclear()
cmd.mdelete('360', '1')

focus('tamra')
cmd.set('ray_trace_mode', '0')
prepareImage()
Image(defaultImage)
Out[15]:

Выберем остаток, к которому присоединим метку. Например, треонин 43.

In [16]:
anchor   = 'original & resi 43'
anchor_O = anchor + ' & n. OG1'

cmd.show('sticks', anchor)
cmd.set('stick_radius', '0.1', anchor)
cmd.set('cartoon_side_chain_helper', 'on')     
focus(anchor)
cmd.color('red', anchor_O)

prepareImage()
Image(defaultImage)
Out[16]:

Присоединим метку к треонину 43.

(Так как атомы разные атомы одного химического элемента в структуре TAMRA не имеют различий в их наименовании, то на этом этапе необходимо воспользоваться GUI PyMol для того, чтобы выбрать атом, к которому будет присоединена метка.)

In [17]:
tamra_C  = '/tamra///UNK`/C'

# NOTE: tamra_C should be choosed manually in PyMol GUI
cmd.fuse(anchor_O, tamra_C)

# torsion 15  # use several times
## And then remove the original oxygen from the TAMRA
In [18]:
new_anchor = 'tamra & i. 43 + /tamra///UNK`/'
cmd.disable('original')
focus(new_anchor)
In [544]:
prepareImage()
Image(defaultImage)
Out[544]:

Построение полиаланиновой α-спирали

Для построения α-спирали из какого-либо аминокислотного остатка нужно сначала выяснить значения углов φ и ψ для этого остатка в α-спиралях известных белков. Для этого можно воспользоваться, например, картой Рамачандрана для интересующего остатка. Для аланина примем значения $ \phi = -50 $ и $ \psi = -40 $. Добавления нового остатка будем производить в цикле, изменяя при этом соответствующие углы для создаваемых остатков.

In [732]:
# Start from scratch
cmd.reinitialize()
cmd.bg_colour('white')

aa  = 'ALA'
ala_phi = '-50'
ala_psi = '-40'
# Or change the torsion angle by these values
# to get the phi and psi needed
ala_shift_phi = '89'
ala_shift_psi = '-175'

def polyAA(n, aa, phi=None, psi=None, shift_phi=None, shift_psi=None):
    cmd.fragment(aa)
    cmd.edit("i. %i & n. C" % 2)
    cmd.edit("i. 2 & n. CA", "i. 2 & n. C")

    # At first, just add all the aminoacids
    for i in range(2, n+1):
        # Choose the atom to attach a new residue to
        cmd.edit("i. %i & n. C" % i)
        cmd.do('editor.attach_amino_acid("pk1", "%s")' % aa)
        time.sleep(1)

    # Then change dihedral angles
    # this way...
    if shift_phi and shift_psi:
        for i in range(2, n+1):
            # Edit the Calpha - C bond of the previous aminoacid
            cmd.edit("i. %i & n. CA" % i,   "i. %i & n. C" % i)
            cmd.do('torsion '+shift_psi)

            # Edit the N - Calpha bond
            cmd.edit("i. %i & n. N" % (i+1),   "i. %i & n. CA" % (i+1))
            cmd.do('torsion '+shift_phi)
    
    # ... or better this way
    elif phi and psi:
        for i in range(2, n+1):
            cmd.set_dihedral("i. %i & n. N" % i, "i. %i & n. CA" % i,
                             "i. %i & n. C" % i, "i. %i & n.  N" % (i+1),
                             phi)
            cmd.set_dihedral("i. %i & n.  C" % i,     "i. %i & n. N" % (i+1),
                             "i. %i & n. CA" % (i+1), "i. %i & n. C" % (i+1),
                             psi)

    cmd.edit()
    cmd.show('cartoon', aa)
    focus(aa)

# polyAA(20, 'ALA', shift_phi=ala_shift_phi, 
#        shift_psi=ala_shift_psi)             # an ugly way
polyAA(100, 'ALA', phi=ala_phi, psi=ala_psi)  # a better way
    
prepareImage()
Image(defaultImage)

# NOTE: I have no idea why the first added aminoacid has resi 2, not 1.
Out[732]:
In [773]:
cmd.set_view('\
            -0.668230056763, 0.238289996982, 0.704759895802, \
            0.72214281559, 0.43547591567, 0.537468612194, \
            -0.178832814097, 0.868088722229, -0.463076025248, \
            -1.80295586586, 4.57921123505, -107.036514282, \
            57.723361969, 39.3814544678, -38.9204406738, \
            -13.3686256409, 227.318893433, -20.0')
    
cmd.hide('everything')
cmd.show('sticks')
cmd.set('stick_radius', '0.1')
cmd.show('spheres')
cmd.set('sphere_scale', '0.3')
cmd.spectrum('count')

prepareImage(); Image(defaultImage)
Out[773]:
In [862]:
## BTW, here's the code to get the current view matrix
# import sys
# for i, u in enumerate((str(i) for i in cmd.get_view())):
#     sys.stdout.write(u)
#     sys.stdout.write(', ')
#     if (i+1)%3 == 0:
#         sys.stdout.write('\\\n')

Построение структуры кубана

С помощью программы babel построим третичную структуру кубана на основе его SMILES-нотации: C12C3C4C1C5C2C3C45.

echo C12C3C4C1C5C2C3C45 > cubane.smi
obgen cubane.smi > cubane.mol
In [791]:
# Start from scratch
cmd.reinitialize()
cmd.bg_colour('white')

cmd.load('cubane.mol')
prepareImage(); Image(defaultImage)
Out[791]:
In [799]:
cmd.hide('everything')
cmd.show('sticks')
cmd.set('stick_radius', '0.1')
cmd.show('spheres')
cmd.set('sphere_scale', '0.2')
cmd.spectrum('count')
focus('cubane')

## Some animation may seem nice
# cmd.mset('1 x180')
# cmd.do('util.mrock(1, 180, 360)')
# cmd.mplay()

prepareImage(300, 200); Image(defaultImage)
Out[799]:

Построение молекулы ДНК

Для построения структуры молекулы ДНК необходимо определить матрицу превращения при совмещении одной пары нуклеотидов с последующей. Затем будем размножать эту пару и применять к ней матрицу превращения.

In [866]:
# We can define a function to parse PyMol syntax
# so that there will be no need to type those cmd-s again
def PyMolExecute(commands):
    one_command = ''
    for line in commands.split('\n'):
        if line:
            one_command += line.strip()
            one_command += '; '
    cmd.do(one_command)

PyMolExecute("""
fetch 1BNA
bg white
hide everything
show cartoon
set cartoon_ring_mode, 2

create pair, c. A & i. 6 + c. B & i. 19
create nextpair, c. A & i. 7 + c. B & i. 18
create 1, pair
pair_fit nextpair, pair
""")

trans = cmd.get_object_matrix("nextpair")
for x in range(2, 100):
    cmd.create(str(x), str(x-1))
    cmd.do('cmd.transform_selection(%i, %s, homogenous=0)' % (x, trans))
    time.sleep(1)

PyMolExecute("""
delete 1BNA
hide everything
show sticks
""")

focus("all")
prepareImage(); Image(defaultImage)
Out[866]:
In [860]:
# Take a close-up view
cmd.show('surface')
cmd.set_view('\
0.279711633921, 0.0657793134451, -0.957828342915, \
-0.955636739731, 0.115004368126, -0.271171957254, \
0.092316634953, 0.991186976433, 0.0950298756361, \
-5.04646450281e-05, 0.000781282782555, -327.234893799, \
21.9157848358, 43.2902755737, 168.800308228, \
-140695.375, 141349.875, -20.0')
prepareImage(); Image(defaultImage)
Out[860]:

Источники, которые были полезны при выполнении заданий:

  1. Анимация: MovieSchool на pymolwiki.org (в частности, MovieSchool 2 и MovieScool 5).
  2. Создание видео: вопросы и ответы про ffmpeg на StackExchange (1, 2).
  3. Редактирование структур: раздел Modelling and Editing Structure на pymolwiki.org.
  4. Двугранные углы: раздел на pymolwiki.org.