Cartographic Plots#
This guide uses the example system loaded in Visualization Example System. Please load the example system before following the rest of the tutorial.
Introduction#
ProteoTwirl calculates angle-dependent properties. This means we have a set of angles indicating where a protein is “viewed” from, and an associated value for each angle.
To plot this, we have to map all angles, which can be seen as points on a sphere, to a flat plane. This is impossible to do without distortion (see Gauss’s Theorema Egregium).
However, many approximate methods with different trade-offs have been developed in cartography to create maps of the Earth. We can reuse these cartographic projections to plot our angle-dependent properties. In practice, ProteoTwirl uses CartoPy to create projections. 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 data points.
The function also creates a scatter plot on top with the original
data points, 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 points 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#
Cartographic contour plots can be made using the plot_carto_contour
function. You must provide arrays of \(\phi\) and \(\theta\) angles,
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 items, in this case floating-point values
print(len(value))
>>> 64
# angles is a 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"
}
)
It is also possible to use categorical values when creating 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 make a scatter plot of the different angles for
a given property using plot_carto_scatter. plot_carto_scatter also
allows scaling and coloring of the scatter points 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 cartographic 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 the same set of angles). We confirm this by using:
hydropathy_angle_space = protein_structure.get_angle_space_of_property("mean_Hydropathy")
alpha_shape_angle_space = protein_structure.get_angle_space_of_property("Alpha_Shape_45_HF20")
print(hydropathy_angle_space == alpha_shape_angle_space)
>>> 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 is shape_size,
which determines the resolution at which the shapes are rendered.
Below is an example of low-resolution rendering (using shape_size = 8
and size = 40, but otherwise the same settings as above).
The other is scale_shape. If True, this will scale the shapes to their correct
relative sizes, allowing better comparison of the size of the protein at different
angles. On the other hand, 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 when it is turned on it can be hard to see
some smaller shapes.
The top plot uses scale_shape = False, and the bottom plot 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 value as central_longitude in the function you are
using (plot_property, plot_shape, plot_carto_contour, or plot_carto_scatter).