Editing structures#

The most basic way to manipulate a structure is to edit the annotation arrays or coordinates directly.

from tempfile import gettempdir
import biotite.database.rcsb as rcsb
import biotite.structure as struc
import biotite.structure.io.pdbx as pdbx

pdbx_file = pdbx.BinaryCIFFile.read(rcsb.fetch("1l2y", "bcif", gettempdir()))
structure = pdbx.get_structure(pdbx_file, model=1)
print("Before:")
print(structure[structure.res_id == 1])
print()
structure.coord += 100
print("After:")
print(structure[structure.res_id == 1])
Before:
    A       1  ASN N      N        -8.901    4.127   -0.555
    A       1  ASN CA     C        -8.608    3.135   -1.618
    A       1  ASN C      C        -7.117    2.964   -1.897
    A       1  ASN O      O        -6.634    1.849   -1.758
    A       1  ASN CB     C        -9.437    3.396   -2.889
    A       1  ASN CG     C       -10.915    3.130   -2.611
    A       1  ASN OD1    O       -11.269    2.700   -1.524
    A       1  ASN ND2    N       -11.806    3.406   -3.543
    A       1  ASN H1     H        -8.330    3.957    0.261
    A       1  ASN H2     H        -8.740    5.068   -0.889
    A       1  ASN H3     H        -9.877    4.041   -0.293
    A       1  ASN HA     H        -8.930    2.162   -1.239
    A       1  ASN HB2    H        -9.310    4.417   -3.193
    A       1  ASN HB3    H        -9.108    2.719   -3.679
    A       1  ASN HD21   H       -11.572    3.791   -4.444
    A       1  ASN HD22   H       -12.757    3.183   -3.294

After:
    A       1  ASN N      N        91.099  104.127   99.445
    A       1  ASN CA     C        91.392  103.135   98.382
    A       1  ASN C      C        92.883  102.964   98.103
    A       1  ASN O      O        93.366  101.849   98.242
    A       1  ASN CB     C        90.563  103.396   97.111
    A       1  ASN CG     C        89.085  103.130   97.389
    A       1  ASN OD1    O        88.731  102.700   98.476
    A       1  ASN ND2    N        88.194  103.406   96.457
    A       1  ASN H1     H        91.670  103.957  100.261
    A       1  ASN H2     H        91.260  105.068   99.111
    A       1  ASN H3     H        90.123  104.041   99.707
    A       1  ASN HA     H        91.070  102.162   98.761
    A       1  ASN HB2    H        90.690  104.417   96.807
    A       1  ASN HB3    H        90.892  102.719   96.321
    A       1  ASN HD21   H        88.428  103.791   95.556
    A       1  ASN HD22   H        87.243  103.183   96.706

Biotite provides also some transformation functions, for example rotate() for rotations about the x-, y- or z-axis.

structure = pdbx.get_structure(pdbx_file, model=1)
print("Before:")
print(structure[structure.res_id == 1])
print()
# Rotation about z-axis by 90 degrees
structure = struc.rotate(structure, [0, 0, np.deg2rad(90)])
print("After:")
print(structure[structure.res_id == 1])
Before:
    A       1  ASN N      N        -8.901    4.127   -0.555
    A       1  ASN CA     C        -8.608    3.135   -1.618
    A       1  ASN C      C        -7.117    2.964   -1.897
    A       1  ASN O      O        -6.634    1.849   -1.758
    A       1  ASN CB     C        -9.437    3.396   -2.889
    A       1  ASN CG     C       -10.915    3.130   -2.611
    A       1  ASN OD1    O       -11.269    2.700   -1.524
    A       1  ASN ND2    N       -11.806    3.406   -3.543
    A       1  ASN H1     H        -8.330    3.957    0.261
    A       1  ASN H2     H        -8.740    5.068   -0.889
    A       1  ASN H3     H        -9.877    4.041   -0.293
    A       1  ASN HA     H        -8.930    2.162   -1.239
    A       1  ASN HB2    H        -9.310    4.417   -3.193
    A       1  ASN HB3    H        -9.108    2.719   -3.679
    A       1  ASN HD21   H       -11.572    3.791   -4.444
    A       1  ASN HD22   H       -12.757    3.183   -3.294

After:
    A       1  ASN N      N        -4.127   -8.901   -0.555
    A       1  ASN CA     C        -3.135   -8.608   -1.618
    A       1  ASN C      C        -2.964   -7.117   -1.897
    A       1  ASN O      O        -1.849   -6.634   -1.758
    A       1  ASN CB     C        -3.396   -9.437   -2.889
    A       1  ASN CG     C        -3.130  -10.915   -2.611
    A       1  ASN OD1    O        -2.700  -11.269   -1.524
    A       1  ASN ND2    N        -3.406  -11.806   -3.543
    A       1  ASN H1     H        -3.957   -8.330    0.261
    A       1  ASN H2     H        -5.068   -8.740   -0.889
    A       1  ASN H3     H        -4.041   -9.877   -0.293
    A       1  ASN HA     H        -2.162   -8.930   -1.239
    A       1  ASN HB2    H        -4.417   -9.310   -3.193
    A       1  ASN HB3    H        -2.719   -9.108   -3.679
    A       1  ASN HD21   H        -3.791  -11.572   -4.444
    A       1  ASN HD22   H        -3.183  -12.757   -3.294

Structure superimposition#

A common prerequisite to compare two structures is the superimposing them onto each other. This means translating and rotating one structure so that the root mean square deviation (RMSD) between corresponding atoms in the two structures is minimized. To demonstrate this, we will use two models of the TC5b structure already used in the previous chapters.

reference = pdbx.get_structure(pdbx_file, model=1)
# Rotate reference to remove the superimposition originating from the file
reference = struc.rotate(reference, [np.deg2rad(45), 0, 0])
mobile = pdbx.get_structure(pdbx_file, model=2)
print(f"RMSD before superimposition: {struc.rmsd(reference, mobile):.2f}")
superimposed, transformation = struc.superimpose(reference, mobile)
print(f"RMSD after superimposition: {struc.rmsd(reference, superimposed):.2f}")
RMSD before superimposition: 4.61
RMSD after superimposition: 1.93

Note

It is required that both structures have the same number (and order) of atoms, as the algorithm requires that each atom corresponds to an atom in the other structure.

The returned AffineTransformation object can be used later to transform another structure in the same way the mobile structure was transformed.

another_model = pdbx.get_structure(pdbx_file, model=3)
print(f"RMSD before transformation: {struc.rmsd(mobile, another_model):.2f}")
# Apply the same transformation that was applied on the mobile structure
transformed = transformation.apply(another_model)
print(f"RMSD after transformation: {struc.rmsd(superimposed, transformed):.2f}")
RMSD before transformation: 1.57
RMSD after transformation: 1.57

We can see that both RMSD values are equal: As the same transformation was applied to mobile and another_model, the atom positions relative to each other did not change.