Collision Cross Section (CCS)#
Ion mobility mass spectrometry (IM-MS) can provide structural information about proteins and other biomolecules by measuring their collision cross sections (CCS).
In this tutorial, we will calculate the CCS for equine heart cytochrome c,
using the 1GIW structure, which can be downloaded from RCSB.
What Is CCS?#
CCS can be thought of as an adjusted average cross-sectional area of a protein. The average cross-sectional area is what we get when we calculate the shape of a protein from different angles, calculate the area of that shape, and take the average of all those areas.
However, CCS is intended to measure how likely a collision between two objects is, and thus the size of the colliding object needs to be taken into account. In IM-MS, that other partner is the buffer gas, often nitrogen or helium.
Important Note on ProteoTwirl CCS#
An important thing to keep in mind when using ProteoTwirl for CCS calculation is that ProteoTwirl will calculate CCS for the structure provided. However, in IM-MS, the protein can exist as ions with different charge states, and the altered charge can change its shape and therefore its CCS value.
Furthermore, if the conformation of the structure provided does not resemble the conformations of the protein in IM-MS, this can add further error and uncertainty to measurements.
Using multiple structures representing different conformations and charge states can help with these inaccuracies.
In this tutorial, we will compare our results to the CCS of the lowest charge state of the protein in experimental data, as we are using a neutral structure as input.
Loading the Protein#
First, we need to load the protein into ProteoTwirl. Because we want to do a CCS calculation, we need to use a special set of atomic radii.
Here we take the normal radii (vdw for van der Waals or cov for covalent)
and add the kinetic radius of the gas that we are using in IM-MS. In this case, we
will be using nitrogen gas ("vdw_N2_adj"), but other gases are available,
such as helium ("vdw_He_adj"), argon ("vdw_Ar_adj"), or xenon ("vdw_Xe_adj").
For more information on loading a protein, see the guide on loading proteins.
import ProteoTwirl.ProteinRotation as pt
protein_structure = pt.ProteinRotation(
protein = "1GIW.pdb",
atom_radii = "vdw_N2_adj",
center_selection = True,
)
We can show the loaded protein as an interactive 3D visualization using the code below. If hydrogens are present, the atomic radii, especially for hydrogen, will appear larger than expected because they have been adjusted for nitrogen gas.
protein_structure.show()
It is important to check whether the structure you are using contains hydrogens. This is not always the case, and for accurate CCS calculation we need hydrogens to be present. You can see our guide on adding hydrogens to a structure in the Loading Protein guide.
Calculating Protein Shape#
The next step is to calculate the shape of the protein when viewed from different angles, as we need this to calculate the area of those shapes.
In ProteoTwirl there are several different methods available to calculate the shape of a protein. For area calculation, the most accurate option available in ProteoTwirl is the disk-overlap method, which is the one we will use here, but it is also the slowest available method. For large proteins or if many angles are needed, other methods may be warranted. For more information, see our guide on shape calculations.
Shapes are a type of property in ProteoTwirl, so we use .add_property. In this
tutorial, we do not use default values, so we set use_default = False
(see the Loading Protein guide for more information on default values),
and we set rotation_res = 64 to sample shapes from 64 different angles.
protein_structure.add_property(
property = "DiskOverlap", # what property to add
use_default = False, # to not use default, we have not set them
rotation_res = 64, # number of angles to sample
)
# when this code runs, it will print
# Adding Disk_Overlap
When this code runs it will say "Adding Disk_Overlap", and Disk_Overlap
is the name of the property added. Note that if you add the property twice the
second time it will have another name like Disk_Overlap_1.
We can use this name to get the shapes of the protein. For example, to get the first shape:
protein_structure.Disk_Overlap[0]
In a Python notebook, this will show the shape like so:
We can also plot all the shapes at the different angles using the .plot_shape
function, which will show them (by default) plotted on an azimuthal equidistant
projection of the viewing angles. See the 2D plotting guide for details.
protein_structure.plot_shape(shape_property="Disk_Overlap", shape_size=45)
Calculating CCS from Shape#
To calculate the CCS, we need the area of each shape. To do this, we need to
add another property: the shape area. This property is a shape property,
which means it is a property of a shape, and requires us to provide the shape for
which the property should be calculated. In this case, that shape is "Disk_Overlap".
We also need to give it the number of angles, which has to match the shape we are using.
protein_structure.add_property(
property = "shape.area",
shape_prop_name = "Disk_Overlap",
use_default = False,
rotation_res = 64
)
# when this code runs, it will print
# Adding Disk_Overlap_area
This will add a property with the name "Disk_Overlap_area". To get the
CCS of a protein, we just need to take the average of this property.
import numpy as np
ccs = np.average(protein_structure.Disk_Overlap_area)
print(ccs)
# 1236.2325161685803
The value of 1236.2 \(Å^2\) is quite close to the 1238 \(Å^2\) reported as the CCS of the lowest charge state here. However, due to the differences in charge state and shape noted in the “Important Note on ProteoTwirl CCS” section, it is quite far from the 1444 \(Å^2\) reported as the mean CCS across all charge states of the protein.
Visualizing CCS#
We can also investigate and visualize the individual shape-area values that make up the final CCS prediction. This can be done using a simple histogram, such as the one shown below:
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_theme(style="white", font_scale=1.1)
fig, ax = plt.subplots(figsize=(7, 4))
sns.histplot(
data = protein_structure.Disk_Overlap_area,
bins = 20,
color = "#2f7f8f",
ax = ax
)
ax.set(
xlabel = r"Collision Cross Section ($\Omega$) Å$^2$",
ylabel = "Number of Viewing Angles",
title = "CCS for Equine Cytochrome C (1GIW)"
)
sns.despine(trim=True)
plt.tight_layout()
plt.show()
However, we can also visualize how the shape size changes with angle using
the .plot_property method, which uses a cartographic projection to show how shape
area changes with viewing angle.
protein_structure.plot_property("Disk_Overlap_area")
We can also create an interactive 3D plot with a sphere for each viewing angle, scaled and colored according to the area.
protein_structure.plot_property_3d("Disk_Overlap_area", background = "#14181e")