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 :ref:`loading_protein`. Following this we will calculate a property and a shape to plot. .. code-block:: python :caption: Loading a Protein from PDB 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 .. raw:: html
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. .. code-block:: python :caption: Calculating Hydropathy of Exposed Residues 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. .. code-block:: python :caption: Calculating Alphashape of Protein 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] .. figure:: ../../_static/Guides/Visualization/8JWX_H_AlphaShape_HF20.svg :figclass: code-output :width: 25% :align: center 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. .. code-block:: python :caption: Property Plot 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 ) .. figure:: ../../_static/Guides/Visualization/8JXW_Hydropathy.png :figclass: code-output :width: 80% :align: center A quick plot showing how a shape looks at different angles can also be made using `plot_shape` as shown below. .. code-block:: python :caption: Shape Plot 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") .. figure:: ../../_static/Guides/Visualization/8JXW_Alpha_Shape.png :figclass: code-output :width: 80% :align: center Contour Plots ------------- Cartography contour plots can be made using the ``plot_carto_contour`` function, where one must provide an array of :math:`\phi` and the :math:`\theta` angle, together with an array of values. Here we will get the angles, and values via the ``get_property`` function, as shown below. .. code-block:: python :caption: Get Property & Angles 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. .. code-block:: python :caption: Plotting using plot_carto_contour 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" } ) .. figure:: ../../_static/Guides/Visualization/8JXW_Hydropathy_contour.png :figclass: code-output :width: 100% :align: center Its also possible to use categorical values when creation contour plots, .. code-block:: python :caption: Plotting using plot_carto_contour 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"} ) .. figure:: ../../_static/Guides/Visualization/8JXW_Hydropathy_contour_categorical.png :figclass: code-output :width: 100% :align: center 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. .. code-block:: python :caption: Plotting using plot_carto_scatter 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") .. figure:: ../../_static/Guides/Visualization/8JXW_Hydropathy_scatter.png :figclass: code-output :width: 100% :align: center 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 : .. code-block:: python :caption: Checking angle-space 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. .. code-block:: python :caption: Checking angle-space 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, }, ) .. figure:: ../../_static/Guides/Visualization/8JXW_Hydropathy_scatter_shape.png :figclass: code-output :width: 100% :align: center 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) .. figure:: ../../_static/Guides/Visualization/8JXW_Hydropathy_scatter_shape_low_res.png :figclass: code-output :width: 100% :align: center 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`` .. figure:: ../../_static/Guides/Visualization/5BU5_scale_False.png :figclass: code-output :width: 100% :align: center .. figure:: ../../_static/Guides/Visualization/5BU5_scale_True.png :figclass: code-output :width: 100% :align: center 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. .. _view3dplot : 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` accordingly - ``show_notebook == False`` will open the visualization in a new webbrowser tab - ``show_notebook == True`` will 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. .. code-block:: python :caption: Notebook Protein protein_structure .. raw:: html
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 :ref:`view3dplot`, allow customization of atom radius and color. For example : .. code-block:: python :caption: Notebook Protein from ProteoTwirl.Visualization.Plot3D import plot_protein plot_protein( protein_rotation = protein_structure, background = "#14181e", atom_color = "Residue", atom_radius = 1.0 ) .. raw:: html
Atomic Color & Radius --------------------- Atomic Radius ............. The radius of atoms in the visualization can be determined in one of three ways, 1) ``atom_radius == None`` in which case the radii from ``protein_rotation`` is used 2) ``atom_radius is float`` in which case all radii is set to this radius 3) ``AtomRadiusFunction``, a function which takes an atom, and additional context as input and provides a radius The ``AtomRadiusFunction`` type function, is defined like shown below .. code-block:: python :caption: Notebook Protein 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. .. code-block:: python :caption: Notebook 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, ) .. raw:: html
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. .. code-block:: python :caption: Notebook Protein plot_protein( protein_rotation = protein_structure, background = "#14181e", atom_color = "Hydropathy Index", ) .. raw:: html
Or thirdly using a ``AtomColorFunction`` which can be defined as such .. code-block:: python :caption: Notebook Protein 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 .. code-block:: python :caption: Notebook Protein 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" ) .. raw:: html
Quick Property View ------------------- .. warning:: Under Construction - Coming Soon .. code-block:: python :caption: Checking angle-space protein_structure.plot_property_3d( property = "mean_Hydropathy", cmap = "RdPu", size_range = (1,20), background = "#14181e", ) .. raw:: html
Plotting Selectors ------------------ .. warning:: Under Construction - Coming Soon Advanced Plotting ----------------- .. warning:: Under Construction - Coming Soon