From d88ca6bd193db31acd00d6045fd3c6b554ccfab9 Mon Sep 17 00:00:00 2001 From: avivko Date: Fri, 13 May 2022 10:55:38 +0200 Subject: [PATCH 1/6] fixes show_edges for the astroid graph --- graphein/protein/visualisation.py | 64 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/graphein/protein/visualisation.py b/graphein/protein/visualisation.py index 3cfbd71d..28680f9b 100644 --- a/graphein/protein/visualisation.py +++ b/graphein/protein/visualisation.py @@ -15,6 +15,7 @@ import networkx as nx import numpy as np import plotly.express as px +import plotly.colors as co import plotly.graph_objects as go import seaborn as sns from mpl_toolkits.mplot3d import Axes3D @@ -118,7 +119,9 @@ def colour_edges( G: nx.Graph, colour_map: matplotlib.colors.ListedColormap, colour_by: str = "kind", -) -> List[Tuple[float, float, float, float]]: + set_alpha=None, + return_as_rgba=False, +) -> List[Tuple[float, float, float, float]] or List[str]: """ Computes edge colours based on the kind of bond/interaction. @@ -128,8 +131,12 @@ def colour_edges( :type colour_map: matplotlib.colors.ListedColormap :param colour_by: Edge attribute to colour by. Currently only ``"kind"`` is supported. :type colour_by: str + :param set_alpha: Sets a given alpha value between 0.0 and 1.0 for all the edge colours. + :type set_alpha: float or None + :param return_as_rgba: Returns a list of rgba strings instead of tuples. + :type return_as_rgba: bool :return: List of edge colours. - :rtype: List[Tuple[float, float, float, float]] + :rtype: List[Tuple[float, float, float, float]] or List[str] """ if colour_by == "kind": edge_types = set( @@ -147,7 +154,15 @@ def colour_edges( raise NotImplementedError( "Other edge colouring methods not implemented." ) - return colors + if set_alpha: + assert (0.0 <= set_alpha <= 1.0) + colors = [c[:3] + (set_alpha,) for c in colors] + if return_as_rgba: + return [ + f"rgba{tuple(list(co.convert_to_RGB_255(c[:3])) + [c[3]])}" for c in colors + ] + else: + return colors def plotly_protein_structure_graph( @@ -654,6 +669,7 @@ def asteroid_plot( colour_nodes_by: str = "shell", # residue_name colour_edges_by: str = "kind", edge_colour_map: plt.cm.Colormap = plt.cm.plasma, + edge_alpha: Optional[float] = None, show_labels: bool = True, title: Optional[str] = None, width: int = 600, @@ -678,6 +694,8 @@ def asteroid_plot( :type colour_edges_by: str :param edge_colour_map: Colour map for edges. Defaults to ``plt.cm.plasma``. :type edge_colour_map: plt.cm.Colormap + :param edge_alpha: Sets a given alpha value between 0.0 and 1.0 for all the edge colours. + :type edge_alpha: float or None :param title: Title of the plot. Defaults to ``None``. :type title: str :param width: Width of the plot. Defaults to ``600``. @@ -715,34 +733,22 @@ def asteroid_plot( if show_edges: edge_colors = colour_edges( - subgraph, colour_map=edge_colour_map, colour_by=colour_edges_by + subgraph, colour_map=edge_colour_map, colour_by=colour_edges_by, + set_alpha=edge_alpha, return_as_rgba=True ) - - edge_x: List[str] = [] - edge_y: List[str] = [] - edge_type: List[str] = [] - for u, v in subgraph.edges(): + edge_trace = [] + for i, (u, v) in enumerate(subgraph.edges()): x0, y0 = subgraph.nodes[u]["pos"] x1, y1 = subgraph.nodes[v]["pos"] - edge_x.append(x0) - edge_x.append(x1) - edge_x.append(None) - edge_y.append(y0) - edge_y.append(y1) - edge_y.append(None) - edge_trace = go.Scatter( - x=edge_x, - y=edge_y, - line=dict(width=1, color=edge_colors), - hoverinfo="text", - mode="lines", - text=[ - " / ".join(list(edge_type)) - for edge_type in nx.get_edge_attributes( - subgraph, "kind" - ).values() - ], - ) + tr = go.Scatter( + x=(x0, x1), + y=(y0, y1), + mode="lines", + line=dict(width=1, color=edge_colors[i]), + hoverinfo="text", + text=[" / ".join(list(subgraph[u][v]["kind"]))], + ) + edge_trace.append(tr) node_x: List[str] = [] node_y: List[str] = [] @@ -789,7 +795,7 @@ def asteroid_plot( ), ) - data = [edge_trace, node_trace] if show_edges else [node_trace] + data = edge_trace + [node_trace] if show_edges else [node_trace] fig = go.Figure( data=data, layout=go.Layout( From b4adecf9cd326a2c1111ac8ebf1f7ffbdc2b6b72 Mon Sep 17 00:00:00 2001 From: avivko Date: Fri, 13 May 2022 10:55:38 +0200 Subject: [PATCH 2/6] fixes show_edges for the asteroid plot --- graphein/protein/visualisation.py | 64 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/graphein/protein/visualisation.py b/graphein/protein/visualisation.py index 3cfbd71d..28680f9b 100644 --- a/graphein/protein/visualisation.py +++ b/graphein/protein/visualisation.py @@ -15,6 +15,7 @@ import networkx as nx import numpy as np import plotly.express as px +import plotly.colors as co import plotly.graph_objects as go import seaborn as sns from mpl_toolkits.mplot3d import Axes3D @@ -118,7 +119,9 @@ def colour_edges( G: nx.Graph, colour_map: matplotlib.colors.ListedColormap, colour_by: str = "kind", -) -> List[Tuple[float, float, float, float]]: + set_alpha=None, + return_as_rgba=False, +) -> List[Tuple[float, float, float, float]] or List[str]: """ Computes edge colours based on the kind of bond/interaction. @@ -128,8 +131,12 @@ def colour_edges( :type colour_map: matplotlib.colors.ListedColormap :param colour_by: Edge attribute to colour by. Currently only ``"kind"`` is supported. :type colour_by: str + :param set_alpha: Sets a given alpha value between 0.0 and 1.0 for all the edge colours. + :type set_alpha: float or None + :param return_as_rgba: Returns a list of rgba strings instead of tuples. + :type return_as_rgba: bool :return: List of edge colours. - :rtype: List[Tuple[float, float, float, float]] + :rtype: List[Tuple[float, float, float, float]] or List[str] """ if colour_by == "kind": edge_types = set( @@ -147,7 +154,15 @@ def colour_edges( raise NotImplementedError( "Other edge colouring methods not implemented." ) - return colors + if set_alpha: + assert (0.0 <= set_alpha <= 1.0) + colors = [c[:3] + (set_alpha,) for c in colors] + if return_as_rgba: + return [ + f"rgba{tuple(list(co.convert_to_RGB_255(c[:3])) + [c[3]])}" for c in colors + ] + else: + return colors def plotly_protein_structure_graph( @@ -654,6 +669,7 @@ def asteroid_plot( colour_nodes_by: str = "shell", # residue_name colour_edges_by: str = "kind", edge_colour_map: plt.cm.Colormap = plt.cm.plasma, + edge_alpha: Optional[float] = None, show_labels: bool = True, title: Optional[str] = None, width: int = 600, @@ -678,6 +694,8 @@ def asteroid_plot( :type colour_edges_by: str :param edge_colour_map: Colour map for edges. Defaults to ``plt.cm.plasma``. :type edge_colour_map: plt.cm.Colormap + :param edge_alpha: Sets a given alpha value between 0.0 and 1.0 for all the edge colours. + :type edge_alpha: float or None :param title: Title of the plot. Defaults to ``None``. :type title: str :param width: Width of the plot. Defaults to ``600``. @@ -715,34 +733,22 @@ def asteroid_plot( if show_edges: edge_colors = colour_edges( - subgraph, colour_map=edge_colour_map, colour_by=colour_edges_by + subgraph, colour_map=edge_colour_map, colour_by=colour_edges_by, + set_alpha=edge_alpha, return_as_rgba=True ) - - edge_x: List[str] = [] - edge_y: List[str] = [] - edge_type: List[str] = [] - for u, v in subgraph.edges(): + edge_trace = [] + for i, (u, v) in enumerate(subgraph.edges()): x0, y0 = subgraph.nodes[u]["pos"] x1, y1 = subgraph.nodes[v]["pos"] - edge_x.append(x0) - edge_x.append(x1) - edge_x.append(None) - edge_y.append(y0) - edge_y.append(y1) - edge_y.append(None) - edge_trace = go.Scatter( - x=edge_x, - y=edge_y, - line=dict(width=1, color=edge_colors), - hoverinfo="text", - mode="lines", - text=[ - " / ".join(list(edge_type)) - for edge_type in nx.get_edge_attributes( - subgraph, "kind" - ).values() - ], - ) + tr = go.Scatter( + x=(x0, x1), + y=(y0, y1), + mode="lines", + line=dict(width=1, color=edge_colors[i]), + hoverinfo="text", + text=[" / ".join(list(subgraph[u][v]["kind"]))], + ) + edge_trace.append(tr) node_x: List[str] = [] node_y: List[str] = [] @@ -789,7 +795,7 @@ def asteroid_plot( ), ) - data = [edge_trace, node_trace] if show_edges else [node_trace] + data = edge_trace + [node_trace] if show_edges else [node_trace] fig = go.Figure( data=data, layout=go.Layout( From 13753d6a1742e894d4fccfe754e0758214e86911 Mon Sep 17 00:00:00 2001 From: avivko <38662498+avivko@users.noreply.github.com> Date: Fri, 13 May 2022 12:11:56 +0200 Subject: [PATCH 3/6] removed an unnecessary else --- graphein/protein/visualisation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/graphein/protein/visualisation.py b/graphein/protein/visualisation.py index 28680f9b..96af546e 100644 --- a/graphein/protein/visualisation.py +++ b/graphein/protein/visualisation.py @@ -161,8 +161,7 @@ def colour_edges( return [ f"rgba{tuple(list(co.convert_to_RGB_255(c[:3])) + [c[3]])}" for c in colors ] - else: - return colors + return colors def plotly_protein_structure_graph( From c22e73e6bf850974fa160bef6771eb1aa561ac34 Mon Sep 17 00:00:00 2001 From: Arian Jamasb Date: Fri, 13 May 2022 11:50:59 +0100 Subject: [PATCH 4/6] minor linting --- graphein/protein/visualisation.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/graphein/protein/visualisation.py b/graphein/protein/visualisation.py index 96af546e..b893f306 100644 --- a/graphein/protein/visualisation.py +++ b/graphein/protein/visualisation.py @@ -119,8 +119,8 @@ def colour_edges( G: nx.Graph, colour_map: matplotlib.colors.ListedColormap, colour_by: str = "kind", - set_alpha=None, - return_as_rgba=False, + set_alpha: float = 1.0, + return_as_rgba: bool = False, ) -> List[Tuple[float, float, float, float]] or List[str]: """ Computes edge colours based on the kind of bond/interaction. @@ -132,7 +132,7 @@ def colour_edges( :param colour_by: Edge attribute to colour by. Currently only ``"kind"`` is supported. :type colour_by: str :param set_alpha: Sets a given alpha value between 0.0 and 1.0 for all the edge colours. - :type set_alpha: float or None + :type set_alpha: float :param return_as_rgba: Returns a list of rgba strings instead of tuples. :type return_as_rgba: bool :return: List of edge colours. @@ -154,9 +154,9 @@ def colour_edges( raise NotImplementedError( "Other edge colouring methods not implemented." ) - if set_alpha: - assert (0.0 <= set_alpha <= 1.0) - colors = [c[:3] + (set_alpha,) for c in colors] + + assert (0.0 <= set_alpha <= 1.0), f"Alpha value {set_alpha} must be between 0.0 and 1.0" + colors = [c[:3] + (set_alpha,) for c in colors] if return_as_rgba: return [ f"rgba{tuple(list(co.convert_to_RGB_255(c[:3])) + [c[3]])}" for c in colors @@ -668,7 +668,7 @@ def asteroid_plot( colour_nodes_by: str = "shell", # residue_name colour_edges_by: str = "kind", edge_colour_map: plt.cm.Colormap = plt.cm.plasma, - edge_alpha: Optional[float] = None, + edge_alpha: float = 1.0, show_labels: bool = True, title: Optional[str] = None, width: int = 600, @@ -694,7 +694,7 @@ def asteroid_plot( :param edge_colour_map: Colour map for edges. Defaults to ``plt.cm.plasma``. :type edge_colour_map: plt.cm.Colormap :param edge_alpha: Sets a given alpha value between 0.0 and 1.0 for all the edge colours. - :type edge_alpha: float or None + :type edge_alpha: float :param title: Title of the plot. Defaults to ``None``. :type title: str :param width: Width of the plot. Defaults to ``600``. From 9be13eb90c0ca9d0f504463df2313ef3925200cf Mon Sep 17 00:00:00 2001 From: avivko Date: Fri, 13 May 2022 21:23:19 +0200 Subject: [PATCH 5/6] adds an interactive legend for the edges --- graphein/protein/visualisation.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/graphein/protein/visualisation.py b/graphein/protein/visualisation.py index b893f306..5286a5b2 100644 --- a/graphein/protein/visualisation.py +++ b/graphein/protein/visualisation.py @@ -675,6 +675,7 @@ def asteroid_plot( height: int = 500, use_plotly: bool = True, show_edges: bool = False, + show_legend: bool = True, node_size_multiplier: float = 10, ) -> Union[plotly.graph_objects.Figure, matplotlib.figure.Figure]: """Plots a k-hop subgraph around a node as concentric shells. @@ -703,8 +704,10 @@ def asteroid_plot( :type height: int :param use_plotly: Use plotly to render the graph. Defaults to ``True``. :type use_plotly: bool - :param show_edges: Whether or not to show edges in the plot. Defaults to ``False``. + :param show_edges: Whether to show edges in the plot. Defaults to ``False``. :type show_edges: bool + :param show_legend: Whether to show the legend of the edges. Fefaults to `True``. + :type show_legend: bool :param node_size_multiplier: Multiplier for the size of the nodes. Defaults to ``10``. :type node_size_multiplier: float. :returns: Plotly figure or matplotlib figure. @@ -735,17 +738,23 @@ def asteroid_plot( subgraph, colour_map=edge_colour_map, colour_by=colour_edges_by, set_alpha=edge_alpha, return_as_rgba=True ) + show_legend_bools = [(True if x not in edge_colors[:i] else False) + for i, x in enumerate(edge_colors)] edge_trace = [] for i, (u, v) in enumerate(subgraph.edges()): x0, y0 = subgraph.nodes[u]["pos"] x1, y1 = subgraph.nodes[v]["pos"] + bond_kind = " / ".join(list(subgraph[u][v]["kind"])) tr = go.Scatter( x=(x0, x1), y=(y0, y1), mode="lines", line=dict(width=1, color=edge_colors[i]), hoverinfo="text", - text=[" / ".join(list(subgraph[u][v]["kind"]))], + text=[bond_kind], + name=bond_kind, + legendgroup=bond_kind, + showlegend=show_legend_bools[i], ) edge_trace.append(tr) @@ -778,6 +787,7 @@ def asteroid_plot( mode="markers+text" if show_labels else "markers", hoverinfo="text", textposition="bottom center", + showlegend=False, marker=dict( colorscale="YlGnBu", reversescale=True, @@ -802,7 +812,13 @@ def asteroid_plot( width=width, height=height, titlefont_size=16, - showlegend=False, + legend=dict( + yanchor="top", + y=1, + xanchor="left", + x=1.10 + ), + showlegend=True if show_legend else False, hovermode="closest", margin=dict(b=20, l=5, r=5, t=40), xaxis=dict( From 7294831987177bbf1c9a39f1c0e068b516cb00a4 Mon Sep 17 00:00:00 2001 From: Arian Jamasb Date: Sat, 14 May 2022 00:05:50 +0100 Subject: [PATCH 6/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1383348b..cb69afa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.5.0 - UNRELEASED +* [Feature] - [#170](https://github.com/a-r-j/graphein/pull/170) Adds support for viewing edges in `graphein.protein.visualisation.asteroid_plot`. Contribution by @avivko. * [Feature] - #163 Adds support for conformer generation for SMILE inputs to molecule graph construction. * [Feature] - #163 Adds support for molecule graph generation from an RDKit.Chem.Mol input. * [Feature] - #163 Adds support for multiprocess molecule graph construction.