Visualization#
ProteoTwirl allows for several different visualization of properties and shapes calculated. Currently visualization is either cartographic projection of properties or shapes, and interactive 3D visualizations of properties.
Example System#
All examples below will be created using the example system presented
below. In this setup we will load in 8JWX with added hydrogens, as
done in Loading Protein. Following this we will calculate a
property and a shape to plot.
import ProteoTwirl.ProteinRotation as pt
protein_structure = pt.ProteinRotation(
protein = "8JXW_H.pdb", # Protein structure to load
selection = "protein and segid E (not element H)", # Select receptor only (in this case segment E)
base_rotation = "principle", # Align to principle axis
center_selection = True, # Set center of geometry to (0,0,0) (center of rotation)
atom_radii = "vdw", # Definiton of radii to use, here van der Waals
# Default values avoids having to re-inter them for each added property
default_rotation_res = 128, # Number of angles to sample
default_rotation_range = None, # Can be set of min and max value for theta and phi angle
default_selectors = None, # Allow us to select atoms based on orientation
default_sampler = None, # how we sample angles, currently only fibonacchi sphere
)
# Show interactive view of the protein loaded
protein_structure
Once the protein is loaded we will calculate a property, in this case we will calculate the average hydropathy index of the exposed residues of the protein.
Hydropathy is a count property and we can add it using the
name "count.Hydropathy", we also need to set the aggregation method to
"mean", as otherwise no aggregation is performed, and we need one value
per angle to plot.
from ProteoTwirl.Selectors.Selector import ExposedAtomSelector
protein_structure.add_property(
property = "count.Hydropathy",
agg_method = "mean",
use_default = False,
rotation_res = 64,
selectors = [ExposedAtomSelector()],
workers = 1
)
>>> Adding mean_Hydropathy
print(len(protein_structure.mean_Hydropathy))
>>> 64
Lastly we will construct a shape of the protein, here we will use an alpha-shape, and apply a small amount of hole-fill to clean up the shape.
protein_structure.add_property(
property = "Alphashape",
hole_fill = 0.2,
use_default = False,
rotation_res = 64,
workers = 1
)
>>> Adding Alpha_Shape_45_HF20
print(len(protein_structure.Alpha_Shape_45_HF20))
>>> 32
protein_structure.Alpha_Shape_45_HF20[0]
Cartographic Plots#
Introduction#
ProteoTwirl calculates angle-dependent properties, this mean we have a set of angles, indicating where a protein is ‘viewed’ from, and an associated value with that angle.
To plot this, we would have to map all angle, which can be seen as points on a sphere, to a flat plane, something which is impossible to due exactly (see Gauss’s Theorema Egregium ).
However many approximate methods with different trade-offs have been made in cartography, to create maps of the earth. We can re-use these cartographic projection to plot our angle-dependent properties. In practice ProteoTwirl uses CartoPy for creating projection, a list of projections available in CartoPy can be found here
Quick Plots#
The easiest way to create a cartographic plot for a given property is
to use the plot_property function. This function will create a contour
plot of the property requested, with interpolation between the datapoints.
The function further creates a scatter-plot on top with the original
datapoints, with point size indicating value.
import cartopy.crs as ccrs
fig,ax = protein_structure.plot_property(
property ="mean_Hydropathy", # name of property
cmap ="RdPu", # matplotlib colormap
projection = ccrs.Stereographic(), # projection
scatter_size =(1,150), # size of scatter plot
interp_degre = 16 # how many point to interpolate
scatter_col = "#222222", # scatter-plot point color
levels = 16 # number of contour levels
)
A quick plot showing how a shape looks at different angles can also be made using plot_shape as shown below.
fig, ax = protein_structure.plot_shape(
shape_property = "Alpha_Shape_45_HF20",
projection = ccrs.EckertIII(),
shape_color = "#ffaaaa",
shape_size = 50,
figsize = (13,8)
)
# Setting a background color, so plot is visible on dark and light mode
# of documentation
ax.patch.set_facecolor("#14181e")
Contour Plots#
Cartography contour plots can be made using the plot_carto_contour
function, where one must provide an array of \(\phi\) and the
\(\theta\) angle, together with an array of values.
Here we will get the angles, and values via the get_property function,
as shown below.
value,angles = protein_structure.get_property(
property_name = "mean_Hydropathy",
return_angle = True
)["mean_Hydropathy"]
# value is a list of item, in this case floating point values
print(len(value))
>>> 64
# angles is an numpy array of phi and theta pairs.
print(angles.shape)
>> (64,2)
These can then be plotted using the plot_carto_contour function, as
shown below.
from ProteoTwirl.Visualization.CatographyPlot import plot_carto_contour
ax = plot_carto_contour(
angles = angles, # angle
values = value, # values/height
projection = ccrs.EckertI(), # projection to use
cmap = "plasma", # matplotlib colormap
figsize = (13,13), # figure size
# gridline can be true/false or a dict with gridline keyword-arguments
gridlines = {
"colors" : "#ffffff"
},
# contour_labels can be true/false or a dict with contour label keyword-arguments
contour_labels = {
"colors" : "#ffffff",
"fmt" : "{:.2f} ".format,
},
# contour_lines can be true/false or a dict with contour line keyword-arguments
contour_lines={
"colors" : "#dddddd",
"linewidths" : 0.6,
"linestyles" :"dashed"
}
)
Its also possible to use categorical values when creation contour plots,
from ProteoTwirl.Visualization.CatographyPlot import plot_carto_contour
value,angles = protein_structure.get_property(
property_name = "mean_Hydropathy",
return_angle = True
)["mean_Hydropathy"]
# Convert to categorical
categorical_values = ["High" if v > 0.7 else "Medium" if v > 0.6 else "Low" for v in value]
ax = plot_carto_contour(
angles = angles,
values = categorical_values,
projection = ccrs.EckertI(),
categorical = True,
figsize = (13,6),
category_colors= {"High" : "#FFaaaa", "Medium" : "#aaFFaa", "Low" : "#aaaaFF"}
)
Scatter Plots#
You can alternatively also do a scatter-plot of the different angles for
a given property using plot_carto_scatter. plot_carto_scatter also
further allows scaling and coloring of the scattered point according to
a value, such as the "mean_Hydropathy" also used for contour plots.
from ProteoTwirl.Visualization.CatographyPlot import plot_carto_scatter
ax = plot_carto_scatter(
angles = angles, # angle
# If string, will color all by same color, but if list of values
# will color according to the colormap in cmap
color = value,
# If single value will use that for all, if array of value will scale
# all sizes to the range of sizes in smin_max_plot, according to their value
size = value,
projection = ccrs.EckertIII(), # projection to use
cmap = "viridis", # matplotlib colormap
figsize = (13,6), # figure size
smin_max_plot = (10,1500), # set min and max marker size
# gridline can be true/false or a dict with gridline keyword-arguments
gridlines = {
"colors" : "#ffffff",
"linewidth" : 1.5,
},
)
# Setting a background color, so plot is visible on dark and light mode
# of documentation
ax.patch.set_facecolor("#14181e")
Shape-Scatter Plots#
The cartography scatter plot also allows you to use custom shapes as the marker-style on the plot. This for example allows us to make a plot showing how the protein looks at different angles.
We can combine this with the hydropathy values from before since they are present in the same angle-space (matching same set of angle). We confirm this by using :
hydropathy_angle_space = protein_structure.get_angle_space_of_property("mean_Hydropathy")
alpha_shape_angle_sapce = protein_structure.get_angle_space_of_property("Alpha_Shape_45_HF20")
print(hydropathy_angle_space == alpha_shape_angle_sapce)
>>> True
We can then plot the shape of the protein, and color it according to the mean hydropathy index of exposed residues from that angle.
shape,angles = protein_structure.get_property(
property_name = "Alpha_Shape_45_HF20",
return_angle = True
)["Alpha_Shape_45_HF20"]
value,_ = protein_structure.get_property(
property_name = "mean_Hydropathy",
return_angle = True
)["mean_Hydropathy"]
ax = plot_carto_scatter(
angles = angles, # angle
color = value,
size = 50,
marker = shape,
projection = ccrs.EckertIII(), # projection to use
cmap = "viridis", # matplotlib colormap
figsize = (13,7), # figure size
# gridline can be true/false or a dict with gridline keyword-arguments
gridlines = {
"colors" : "#ffffff",
"linewidth" : 1.5,
},
)
When plotting shapes, there are two additional options to keep in mind
for how the shapes are rendered. The first of these are shape_size,
which determines how high of a resolution the shapes are rendered in,
below is shown an example of low resolution rendering (using shape_size = 8
and size = 40, but otherwise same as above)
The other is scale_shape, which if True will scale the shapes their relative
correct sizes, allowing better comparison of the size of protein at different
angles. On the otherhand this can make some angles hard to see if they are small,
and it precludes scaling the shapes according to some value.
Below is an example of a very elongated protein (5BU5) where scale_shape is
either turned on or off, highlighting that with it on it can be hard to see
some smaller shapes.
Top plot uses scale_shape = False, and bottom uses scale_shape = True
Note on Central Longitude#
Note that if you change the central_longitude in a projection, then you need
to specify that as well in for the central_longitude in the function you are
using (plot_property, plot_shpae, plot_carto_contour or plot_carto_scatter)
Interactive 3D Plots#
ProteoTwirl also supports various interactive 3D plots. These visualizations will show the protein in the center, with sphere around it indicating the different angles the protein is viewed at.
Viewing & Saving 3D Plots#
When viewing an interactive 3D visualization, there are two different ways to do this. Either they can be viewed in a python notebook, or they can be opened in an external webrowser.
In the plots following, this is controlled by show_notebook variable. This
can be set to one of three different values.
show_notebook == None(default) : will try to check if the code is executed in a notebook, and automatically set show_notebook accordinglyshow_notebook == Falsewill open the visualization in a new webbrowser tabshow_notebook == Truewill show the visualization as a notebook widget
To save a 3D visualization, you can set html_path to a string indicating where
the visualization should be saved. 3D visualization are saved as HTML files.
Plotting Protein#
The easiest way to visualize a protein, in a python notebook, is simply
ending a cell with a ProteinRotation object, which will show an
interactive 3D ball-representation of the protein.
protein_structure
However more customizable visualization, and visualization outside the
notebook context, is available using the plot_protein function. Here
in addition to the view/save arguments discussed in Viewing & Saving 3D Plots,
allow customization of atom radius and color. For example :
from ProteoTwirl.Visualization.Plot3D import plot_protein
plot_protein(
protein_rotation = protein_structure,
background = "#14181e",
atom_color = "Residue",
atom_radius = 1.0
)
Atomic Color & Radius#
Atomic Radius#
The radius of atoms in the visualization can be determined in one of three ways,
atom_radius == Nonein which case the radii fromprotein_rotationis usedatom_radius is floatin which case all radii is set to this radiusAtomRadiusFunction, a function which takes an atom, and additional context as input and provides a radius
The AtomRadiusFunction type function, is defined like shown below
def radii_function (
index,
angle,
val,
atom,
radius,
)-> float :
Here index will be the index of the angle in question, angle is a tuple
of the angle we are currently look at the protien at, if sliders are used, this
can allow radius to change depending on which angle is selected, val is related
to a potential value associated with that angle, atom is the MDAnalysis Atom
to calculate radius from, and radius is the radius retrived from the
protein_rotation object.
An example custom function is presented below, which sizes each atom based on the index it has in the protein.
def radii_function (
index,
angle,
val,
atom,
radius,
)-> float :
# atom index start at 12000 due to selection of one segment
radii = np.sqrt(atom.id - 12000)/(100)
return radii
plot_protein(
protein_rotation = protein_structure,
background = "#14181e",
atom_color = "Element",
atom_radius = radii_function,
)
Atom Color#
The color of each atom in the visualization can also be customized, here there are three different options for color,
Firstly as a string indicating a constant color, such a hex-color code
Secondly as a string for either one of the predefined color schemes
- "Element" : color each atom by their element
- "Residue" : color each atom by the Residue
or the name of one of the residue count-properties, in which case
they will be colored according to the residue value.
plot_protein(
protein_rotation = protein_structure,
background = "#14181e",
atom_color = "Hydropathy Index",
)
Or thirdly using a AtomColorFunction which can be defined as such
def color_function (
index,
angle,
val,
atom,
)-> str|tuple[float,float,float] :
Here index will be the index of the angle in question, angle is a tuple
of the angle we are currently look at the protien at, if sliders are used, this
can allow color to change depending on which angle is selected, val is related
to a potential value associated with that angle, atom is the MDAnalysis Atom
to calculate color for. The output should either by a string for a color
def color_function (
index,
angle,
val,
atom,
) :
# Scale to roughly fit 0-255 scale for red
id_to_int = int(np.sqrt(atom.id - 12000)/(0.3))
color = format(id_to_int, "02x") + "0000"
return color
plot_protein(
protein_rotation = protein_structure,
background = "#14181e",
atom_color = color_function,
html_path = "3D_Custom_Color_Function.html"
)
Quick Property View#
Warning
Under Construction - Coming Soon
protein_structure.plot_property_3d(
property = "mean_Hydropathy",
cmap = "RdPu",
size_range = (1,20),
background = "#14181e",
)
Plotting Selectors#
Warning
Under Construction - Coming Soon
Advanced Plotting#
Warning
Under Construction - Coming Soon