The nodes of the human disease network (HDN) are disorders,
and two disorders are connected if they share a genetic component. In order to identify the disorders that have common genetic components
with a given node, we are clicking that node and on_click
is executed a callback that performs a kind of neighboring nodes selection.
import platform
print(f'Python version: {platform.python_version()}')
Python version: 3.7.3
import plotly
plotly.__version__
'4.8.1'
import igraph as ig
import numpy as np
import ast
import plotly.graph_objs as go
import ipywidgets as ipw
Read the gml
file as an igraph.Graph
:
K = ig.Graph.Read_GML('human-disease.gml')
The following function extracts from the graph K, the data needed to plot it via Plotly:
def get_Plotly_netw(G, graph_layout, title='Plotly Interactive Human Disease Network',
source=None, flip='lr', width=950, height=790): #h=850
# G is an igraph.Graph instance
# graph_layout is an igraph.Layout instance
# title - the network title
# flip is one of the strings 'lr', 'ud' to get a pseudo-flip effect
# the igraph.Layout is referenced to the screen system of coords, and is upside-down flipped chonging the sign of y-coords
# the global HDN looks better with the left-right flipped layout, by changing the x-coords sign.
#width and height are the sizes of the plot area
graph_layout = np.array(graph_layout)
if flip == 'lr':
graph_layout[:,0] =- graph_layout[:,0]
elif flip == 'ud':
graph_layout[:,1] =- graph_layout[:,1]
else:
raise ValueError('There is no such a flip type')
m = len(G.vs)
graph_edges = [e.tuple for e in G.es]# represent edges as tuples of end vertex indices
Xn = [graph_layout[k][0] for k in range(m)]#x-coordinates of graph nodes(vertices)
Yn = [graph_layout[k][1] for k in range(m)]#y-coordinates -"-
Xe = []#list of edge ends x-coordinates
Ye = []#list of edge ends y-coordinates
for e in graph_edges:
Xe.extend([graph_layout[e[0]][0],graph_layout[e[1]][0], None])
Ye.extend([graph_layout[e[0]][1],graph_layout[e[1]][1], None])
size = [vertex['size'] for vertex in G.vs]
#define the Plotly graphical objects
plotly_edges = go.Scatter(x=Xe,
y=Ye,
mode='lines',
line=dict(color='rgb(180,180,180)', width=0.75),
hoverinfo='none')
plotly_vertices = go.Scatter(x=Xn,
y=Yn,
mode='markers',
name='',
marker=dict(symbol='circle-dot',
size=size,
color=[vertex['color'] for vertex in G.vs],
line=dict(color='rgb(50,50,50)', width=0.5)
),
text=[f"{vertex['label']}<br>({vertex['disclass']})" for vertex in G.vs],
hoverinfo='text')
#Define the Plotly plot layout:
plotly_plot_layout = dict(title=title,
width=width,
height=height,
showlegend=False,
xaxis_visible=False,
yaxis_visible=False,
margin=dict(t=100, b=5),
hovermode='closest',
paper_bgcolor='rgb(235,235,235)',
template='none'
)
if source is not None:
annotations = [dict(showarrow=False,
text=source,
xref='paper',
yref='paper',
x=0,
y=-0.1,
xanchor='left',
yanchor='bottom',
font=dict(size=14)
)]
else:
annotations = []
disorder_name = [vertex['label'] for vertex in G.vs]
for k, s in enumerate(size):
if s>= 20:
annotations.append(dict(text=disorder_name[k],
x=graph_layout[k][0],
y=graph_layout[k][1],
xref='x1', yref='y1',
font=dict(color='rgb(50,50,50)', size=10),
showarrow=False))
plotly_plot_layout.update(annotations=annotations)
return go.FigureWidget(data=[plotly_edges, plotly_vertices], layout=plotly_plot_layout)
Since the position of each node is recorded as a string, we convert it to a tuple of floats:
pos = [ast.literal_eval(v['position']) for v in K.vs]
HDN_layout = np.array(pos)
fig = get_Plotly_netw(K, HDN_layout)
The callback function associated to a node click event, extracts the neighbhoring nodes of the clicked one, color the subset
of these nodes with the same color, at choice, and the complementary nodes with gray. At the same time a Text
widget displays the label and disorder class of the clicked disorder.
textbox = ipw.Text(value='',
description='Neighbors of:',
disabled=False,
continuous_update=True)
textbox.layout = dict(margin='-35px 10px 10px 410px', width='450px') # place the textbox at the bottom right corner
# of the plotarea
def select_neighbors(trace, points, state):
if not points.point_inds:
return
ind = points.point_inds[0]
new_color = np.array(['rgba(230, 230, 230, 0.9)']*len(trace.x))
# extract the indices of the clicked vertex neighbors
I = np.append(np.unique(np.array(K.neighbors(ind, mode='out'))), [ind])
new_color[I] = K.vs[ind]['color'] #color all neighbors with the color of the clicked node or with 'rgba(240, 0, 0, 0.9)'
trace.marker.color = new_color
textbox.value = f"{K.vs[ind]['label']} ({K.vs[ind]['disclass']})"
fig.data[1].on_click(select_neighbors)
ipw.VBox([fig, textbox])
VBox(children=(FigureWidget({ 'data': [{'hoverinfo': 'none', 'line': {'color': 'rgb(180,180,…
%%html
<img src='click-event-listener.gif'>