Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
836 lines (698 sloc)
32.4 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
-------------------------------------------------------- | |
Authors: | |
- Brin Rosenthal (sbrosenthal@ucsd.edu) | |
- Julia Len (jlen@ucsd.edu) | |
- Mikayla Webster (13webstermj@gmail.com) | |
-------------------------------------------------------- | |
''' | |
from __future__ import print_function | |
import json | |
import math | |
import matplotlib as mpl | |
import matplotlib.pyplot as plt | |
import networkx as nx | |
import numpy as np | |
import pandas as pd | |
#import visJS_module # use this for local testing | |
import visJS2jupyter.visJS_module as visJS_module | |
import scipy_heatKernel | |
def draw_graph_overlap(G1, G2, | |
edge_cmap=plt.cm.coolwarm, | |
export_file='graph_overlap.json', | |
export_network=False, | |
highlight_nodes=None, | |
k=None, | |
node_cmap=plt.cm.autumn, | |
node_name_1='graph 1', | |
node_name_2='graph 2', | |
node_size=10, | |
physics_enabled=False, | |
**kwargs): | |
''' | |
Takes two networkX graphs and displays their overlap, where intersecting | |
nodes are triangles. Additional kwargs are passed to visjs_module. | |
Inputs: | |
- G1: a networkX graph | |
- G2: a networkX graph | |
- edge_cmap: matplotlib colormap for edges, default: matplotlib.cm.coolwarm | |
- export_file: JSON file to export graph data, default: 'graph_overlap.json' | |
- export_network: export network to Cytoscape, default: False | |
- highlight_nodes: list of nodes to place borders around, default: None | |
- k: float, optimal distance between nodes for nx.spring_layout(), default: None | |
- node_cmap: matplotlib colormap for nodes, default: matplotlib.cm.autumn | |
- node_name_1: string to name first graph's nodes, default: 'graph 1' | |
- node_name_2: string to name second graph's nodes, default: 'graph 2' | |
- node_size: size of nodes, default: 10 | |
- physics_enabled: enable physics simulation, default: False | |
Returns: | |
- VisJS html network plot (iframe) of the graph overlap. | |
''' | |
G_overlap = create_graph_overlap(G1, G2, node_name_1, node_name_2) | |
# create nodes dict and edges dict for input to visjs | |
nodes = list(G_overlap.nodes()) | |
edges = list(G_overlap.edges()) | |
# set the position of each node | |
if k is None: | |
pos = nx.spring_layout(G_overlap) | |
else: | |
pos = nx.spring_layout(G_overlap,k=k) | |
xpos,ypos=zip(*pos.values()) | |
nx.set_node_attributes(G_overlap, name = 'xpos', values = dict(zip(pos.keys(),[x*1000 for x in xpos]))) | |
nx.set_node_attributes(G_overlap, name = 'ypos', values = dict(zip(pos.keys(),[y*1000 for y in ypos]))) | |
# set the border width of nodes | |
if 'node_border_width' not in kwargs.keys(): | |
kwargs['node_border_width'] = 2 | |
border_width = {} | |
for n in nodes: | |
if highlight_nodes is not None and n in highlight_nodes: | |
border_width[n] = kwargs['node_border_width'] | |
else: | |
border_width[n] = 0 | |
nx.set_node_attributes(G_overlap, name = 'nodeOutline', values = border_width) | |
# set the shape of each node | |
nodes_shape=[] | |
for node in G_overlap.nodes(data=True): | |
if node[1]['node_overlap']==0: | |
nodes_shape.append('dot') | |
elif node[1]['node_overlap']==2: | |
nodes_shape.append('square') | |
elif node[1]['node_overlap']==1: | |
nodes_shape.append('triangle') | |
node_to_shape=dict(zip(G_overlap.nodes(),nodes_shape)) | |
nx.set_node_attributes(G_overlap, name = 'nodeShape', values = node_to_shape) | |
# set the node label of each node | |
if highlight_nodes: | |
node_labels = {} | |
for node in nodes: | |
if node in highlight_nodes: | |
node_labels[node] = str(node) | |
else: | |
node_labels[node] = '' | |
else: | |
node_labels = {n:str(n) for n in nodes} | |
nx.set_node_attributes(G_overlap, name = 'nodeLabel', values = node_labels) | |
# set the node title of each node | |
node_titles = [ node[1]['node_name_membership'] + '<br/>' + str(node[0]) | |
for node in G_overlap.nodes(data=True) ] | |
node_titles = dict(zip(G_overlap.nodes(),node_titles)) | |
nx.set_node_attributes(G_overlap, name = 'nodeTitle', values = node_titles) | |
# set color of each node | |
node_to_color = visJS_module.return_node_to_color(G_overlap, | |
field_to_map='node_overlap', | |
cmap=node_cmap, | |
color_max_frac=.9, | |
color_min_frac=.1) | |
# set color of each edge | |
edge_to_color = visJS_module.return_edge_to_color(G_overlap, | |
field_to_map='edge_weight', | |
cmap=edge_cmap, | |
alpha=.3) | |
# create the nodes_dict with all relevant fields | |
nodes_dict = [{'id':str(n), | |
'border_width':border_width[n], | |
'color':node_to_color[n], | |
'degree':G_overlap.degree(n), | |
'node_label':node_labels[n], | |
'node_shape':node_to_shape[n], | |
'node_size':node_size, | |
'title':node_titles[n], | |
'x':np.float64(pos[n][0]).item()*1000, | |
'y':np.float64(pos[n][1]).item()*1000} | |
for n in nodes] | |
# map nodes to indices for source/target in edges | |
node_map = dict(zip(nodes,range(len(nodes)))) | |
# create the edges_dict with all relevant fields | |
edges_dict = [{'source':node_map[edges[i][0]], | |
'target':node_map[edges[i][1]], | |
'color':edge_to_color[edges[i]]} | |
for i in range(len(edges))] | |
# set node_size_multiplier to increase node size as graph gets smaller | |
if 'node_size_multiplier' not in kwargs.keys(): | |
if len(nodes) > 500: | |
kwargs['node_size_multiplier'] = 3 | |
elif len(nodes) > 200: | |
kwargs['node_size_multiplier'] = 5 | |
else: | |
kwargs['node_size_multiplier'] = 7 | |
kwargs['physics_enabled'] = physics_enabled | |
# if node hovering color not set, set default to black | |
if 'node_color_hover_background' not in kwargs.keys(): | |
kwargs['node_color_hover_background'] = 'black' | |
# node size determined by size in nodes_dict, not by id | |
if 'node_size_field' not in kwargs.keys(): | |
kwargs['node_size_field'] = 'node_size' | |
# node label determined by value in nodes_dict | |
if 'node_label_field' not in kwargs.keys(): | |
kwargs['node_label_field'] = 'node_label' | |
# export the network to JSON for Cytoscape | |
if export_network: | |
node_colors = map_node_to_color(G_overlap,'node_overlap',False) | |
nx.set_node_attributes(G_overlap, name = 'nodeColor', values = node_colors) | |
edge_colors = map_edge_to_color(G_overlap,'edge_weight',False) | |
nx.set_edge_attributes(G_overlap, name = 'edgeColor', values = edge_colors) | |
visJS_module.export_to_cytoscape(G = G_overlap, export_file = export_file) | |
return visJS_module.visjs_network(nodes_dict,edges_dict,**kwargs) | |
def create_graph_overlap(G1,G2,node_name_1,node_name_2): | |
''' | |
Create and return the overlap of two graphs. | |
Inputs: | |
- G1: a networkX graph | |
- G2: a networkX graph | |
- node_name_1: string to name first graph's nodes | |
- node_name_2: string to name second graph's nodes | |
Returns: | |
- A networkX graph that is the overlap of G1 and G2. | |
''' | |
overlap_graph = nx.Graph() | |
node_union = list(np.union1d(list(G1.nodes()),list(G2.nodes()))) | |
node_intersect = list(np.intersect1d(list(G1.nodes()),list(G2.nodes()))) | |
nodes_1only = np.setdiff1d(list(G1.nodes()),node_intersect) | |
nodes_2only = np.setdiff1d(list(G2.nodes()),node_intersect) | |
edges_total = list(G1.edges()) | |
edges_total.extend(list(G2.edges())) | |
overlap_graph.add_nodes_from(node_union) | |
# set node attributes to distinguish which graph the node belongs to | |
node_overlap=[] | |
node_name_membership=[] | |
for node in node_union: | |
if node in nodes_1only: | |
node_overlap.append(0) | |
node_name_membership.append(node_name_1) | |
elif node in nodes_2only: | |
node_overlap.append(2) | |
node_name_membership.append(node_name_2) | |
else: | |
node_overlap.append(1) | |
node_name_membership.append(node_name_1+' + '+node_name_2) | |
nx.set_node_attributes(overlap_graph, | |
name = 'node_overlap', | |
values = dict(zip(node_union,node_overlap))) | |
nx.set_node_attributes(overlap_graph, | |
name = 'node_name_membership', | |
values = dict(zip(node_union,node_name_membership))) | |
nodes_total = list(overlap_graph.nodes()) | |
intersecting_edge_val = int(math.floor(math.log10(len(nodes_total)))) * 10 | |
# set the edge weights | |
edge_weights = {} | |
for e in edges_total: | |
eflip = (e[1],e[0]) | |
if (e in edge_weights.keys()): | |
edge_weights[e]+=intersecting_edge_val | |
elif (eflip in edge_weights.keys()): | |
edge_weights[eflip]+=intersecting_edge_val | |
else: | |
edge_weights[e]=1 | |
v1,v2 = zip(*edge_weights.keys()) | |
weights = edge_weights.values() | |
edges = zip(v1,v2,weights) | |
overlap_graph.add_weighted_edges_from(edges) | |
nx.set_edge_attributes(overlap_graph, name = 'edge_weight', values = edge_weights) | |
return overlap_graph | |
def draw_heat_prop(G, seed_nodes, random_walk = True, | |
edge_cmap=plt.cm.autumn_r, | |
export_file='heat_prop.json', | |
export_network=False, | |
highlight_nodes=None, | |
k=None, | |
largest_connected_component=False, | |
node_cmap=plt.cm.autumn_r, | |
node_size=10, | |
num_nodes=None, | |
physics_enabled=False, | |
Wprime=None, | |
**kwargs): | |
''' | |
Implements and displays the network propagation for a given graph and seed | |
nodes. Additional kwargs are passed to visJS_module. | |
Inputs: | |
- G: a networkX graph | |
- seed_nodes: nodes on which to initialize the simulation (must be a dict if random_walk = False) | |
- random_walk: True to perform a random walk style heat propagation, False to perform a diffusion style one. | |
- edge_cmap: matplotlib colormap for edges, default: matplotlib.cm.autumn_r | |
- export_file: JSON file to export graph data, default: 'graph_overlap.json' | |
- export_network: export network to Cytoscape, default: False | |
- highlight_nodes: list of nodes to place borders around, default: None | |
- k: float, optimal distance between nodes for nx.spring_layout(), default: None | |
- largest_connected_component: boolean, whether or not to display largest_connected_component, | |
default: False | |
- node_cmap: matplotlib colormap for nodes, default: matplotlib.cm.autumn_r | |
- node_size: size of nodes, default: 10 | |
- num_nodes: the number of the hottest nodes to graph, default: None (all nodes will be graphed) | |
- physics_enabled: enable physics simulation, default: False | |
- Wprime: normalized adjacency matrix (from function normalized_adj_matrix()) | |
Returns: | |
- VisJS html network plot (iframe) of the heat propagation. | |
''' | |
# check for invalid nodes in seed_nodes | |
invalid_nodes = [node for node in seed_nodes if node not in G.nodes()] | |
for node in invalid_nodes: | |
print ('Node {} not in graph'.format(node)) | |
if invalid_nodes: | |
return | |
# perform the network propagation | |
if random_walk == True: # perform random walk style heat propagation | |
if Wprime is None: | |
Wprime = normalized_adj_matrix(G) | |
prop_graph = network_propagation(G, Wprime, seed_nodes).to_dict() | |
nx.set_node_attributes(G, name = 'node_heat', values = prop_graph) | |
else: # perform diffusion style heat propagation | |
if (type(seed_nodes) == list): # if the user supplies a list, convert to dict | |
one_list = [1]*len(seed_nodes) # all seed nodes get start value of 1 | |
seed_nodes = dict(zip(seed_nodes, one_list)) | |
elif (type(seed_nodes) != dict): | |
print('seed_nodes must be a list or a dict') | |
return -1 | |
heat_kernel = scipy_heatKernel.SciPYKernel(G) # need a graph | |
diffused_heats = heat_kernel.diffuse(seed_nodes) # need seed_to_heat mapping | |
nx.set_node_attributes(G, name = 'node_heat', values = dict(diffused_heats)) | |
# find top num_nodes hottest nodes and connected component if requested | |
G = set_num_nodes(G,num_nodes) | |
if largest_connected_component: | |
G = max(nx.connected_component_subgraphs(G), key=len) | |
nodes = list(G.nodes()) | |
edges = list(G.edges()) | |
# check for empty nodes and edges after getting subgraph of G | |
if not nodes: | |
print ('There are no nodes in the graph. Try increasing num_nodes.') | |
return | |
if not edges: | |
print ('There are no edges in the graph. Try increasing num_nodes.') | |
return | |
# set the position of each node | |
if k is None: | |
pos = nx.spring_layout(G) | |
else: | |
pos = nx.spring_layout(G,k=k) | |
xpos,ypos=zip(*pos.values()) | |
nx.set_node_attributes(G, name = 'xpos', values = dict(zip(pos.keys(),[x*1000 for x in xpos]))) | |
nx.set_node_attributes(G, name = 'ypos', values = dict(zip(pos.keys(),[y*1000 for y in ypos]))) | |
# set the border width of nodes | |
if 'node_border_width' not in kwargs.keys(): | |
kwargs['node_border_width'] = 2 | |
border_width = {} | |
for n in nodes: | |
if n in seed_nodes: | |
border_width[n] = kwargs['node_border_width'] | |
elif highlight_nodes is not None and n in highlight_nodes: | |
border_width[n] = kwargs['node_border_width'] | |
else: | |
border_width[n] = 0 | |
nx.set_node_attributes(G, name = 'nodeOutline', values = border_width) | |
# set the shape of each node | |
nodes_shape=[] | |
for node in G.nodes(): | |
if node in seed_nodes: | |
nodes_shape.append('triangle') | |
else: | |
nodes_shape.append('dot') | |
node_to_shape=dict(zip(G.nodes(),nodes_shape)) | |
nx.set_node_attributes(G, name = 'nodeShape', values = node_to_shape) | |
# add a field for node labels | |
if highlight_nodes: | |
node_labels = {} | |
for node in nodes: | |
if node in seed_nodes: | |
node_labels[node] = str(node) | |
elif node in highlight_nodes: | |
node_labels[node] = str(node) | |
else: | |
node_labels[node] = '' | |
else: | |
node_labels = {n:str(n) for n in nodes} | |
nx.set_node_attributes(G, name = 'nodeLabel', values = node_labels) | |
# set title for each node | |
node_titles = [str(node[0]) + '<br/>heat = ' + str(round(node[1]['node_heat'],5)) | |
for node in G.nodes(data=True)] | |
node_titles = dict(zip(G.nodes(),node_titles)) | |
nx.set_node_attributes(G, name = 'nodeTitle', values = node_titles) | |
# set color of each node | |
node_to_color = visJS_module.return_node_to_color(G, | |
field_to_map='node_heat', | |
cmap=node_cmap, | |
color_vals_transform='log') | |
# set heat value of edge based off hottest connecting node's value | |
node_attr = nx.get_node_attributes(G,'node_heat') | |
edge_weights = {} | |
for e in edges: | |
if node_attr[e[0]] > node_attr[e[1]]: | |
edge_weights[e] = node_attr[e[0]] | |
else: | |
edge_weights[e] = node_attr[e[1]] | |
nx.set_edge_attributes(G, name = 'edge_weight', values = edge_weights) | |
# set color of each edge | |
edge_to_color = visJS_module.return_edge_to_color(G, | |
field_to_map='edge_weight', | |
cmap=edge_cmap, | |
color_vals_transform='log') | |
# create the nodes_dict with all relevant fields | |
nodes_dict = [{'id':str(n), | |
'border_width':border_width[n], | |
'degree':G.degree(n), | |
'color':node_to_color[n], | |
'node_label':node_labels[n], | |
'node_size':node_size, | |
'node_shape':node_to_shape[n], | |
'title':node_titles[n], | |
'x':np.float64(pos[n][0]).item()*1000, | |
'y':np.float64(pos[n][1]).item()*1000} for n in nodes] | |
# map nodes to indices for source/target in edges | |
node_map = dict(zip(nodes,range(len(nodes)))) | |
# create the edges_dict with all relevant fields | |
edges_dict = [{'source':node_map[edges[i][0]], | |
'target':node_map[edges[i][1]], | |
'color':edge_to_color[edges[i]]} for i in range(len(edges))] | |
# set node_size_multiplier to increase node size as graph gets smaller | |
if 'node_size_multiplier' not in kwargs.keys(): | |
if len(nodes) > 500: | |
kwargs['node_size_multiplier'] = 3 | |
elif len(nodes) > 200: | |
kwargs['node_size_multiplier'] = 5 | |
else: | |
kwargs['node_size_multiplier'] = 7 | |
kwargs['physics_enabled'] = physics_enabled | |
# if node hovering color not set, set default to black | |
if 'node_color_hover_background' not in kwargs.keys(): | |
kwargs['node_color_hover_background'] = 'black' | |
# node size determined by size in nodes_dict, not by id | |
if 'node_size_field' not in kwargs.keys(): | |
kwargs['node_size_field'] = 'node_size' | |
# node label determined by value in nodes_dict | |
if 'node_label_field' not in kwargs.keys(): | |
kwargs['node_label_field'] = 'node_label' | |
# export the network to JSON for Cytoscape | |
if export_network: | |
node_colors = map_node_to_color(G,'node_heat',True) | |
nx.set_node_attributes(G, name = 'nodeColor', values = node_colors) | |
edge_colors = map_edge_to_color(G,'edge_weight',True) | |
nx.set_edge_attributes(G, name = 'edgeColor', values = edge_colors) | |
visJS_module.export_to_cytoscape(G = G,export_file = export_file) | |
return visJS_module.visjs_network(nodes_dict,edges_dict,**kwargs) | |
def draw_colocalization(G, seed_nodes_1, seed_nodes_2, | |
edge_cmap=plt.cm.autumn_r, | |
export_file='colocalization.json', | |
export_network=False, | |
highlight_nodes=None, | |
k=None, | |
largest_connected_component=False, | |
node_cmap=plt.cm.autumn_r, | |
node_size=10, | |
num_nodes=None, | |
physics_enabled=False, | |
Wprime=None, | |
**kwargs): | |
''' | |
Implements and displays the network propagation for a given graph and two | |
sets of seed nodes. Additional kwargs are passed to visJS_module. | |
Inputs: | |
- G: a networkX graph | |
- seed_nodes_1: first set of nodes on which to initialize the simulation | |
- seed_nodes_2: second set of nodes on which to initialize the simulation | |
- edge_cmap: matplotlib colormap for edges, optional, default: matplotlib.cm.autumn_r | |
- export_file: JSON file to export graph data, default: 'colocalization.json' | |
- export_network: export network to Cytoscape, default: False | |
- highlight_nodes: list of nodes to place borders around, default: None | |
- k: float, optional, optimal distance between nodes for nx.spring_layout(), default: None | |
- largest_connected_component: boolean, optional, whether or not to display largest_connected_component, | |
default: False | |
- node_cmap: matplotlib colormap for nodes, optional, default: matplotlib.cm.autumn_r | |
- node_size: size of nodes, default: 10 | |
- num_nodes: the number of the hottest nodes to graph, default: None (all nodes will be graphed) | |
- physics_enabled: enable physics simulation, default: False | |
- Wprime: Normalized adjacency matrix (from normalized_adj_matrix) | |
Returns: | |
- VisJS html network plot (iframe) of the colocalization. | |
''' | |
# check for invalid nodes in seed_nodes | |
invalid_nodes = [(node,'seed_nodes_1') for node in seed_nodes_1 if node not in G.nodes()] | |
invalid_nodes.extend([(node,'seed_nodes_2') for node in seed_nodes_2 if node not in G.nodes()]) | |
for node in invalid_nodes: | |
print ('Node {} in {} not in graph'.format(node[0], node[1])) | |
if invalid_nodes: | |
return | |
# perform the colocalization | |
if Wprime is None: | |
Wprime = normalized_adj_matrix(G) | |
prop_graph_1 = network_propagation(G, Wprime, seed_nodes_1).to_dict() | |
prop_graph_2 = network_propagation(G, Wprime, seed_nodes_2).to_dict() | |
prop_graph = {node:(prop_graph_1[node]*prop_graph_2[node]) for node in prop_graph_1} | |
nx.set_node_attributes(G, name = 'node_heat', values = prop_graph) | |
# find top num_nodes hottest nodes and connected component if requested | |
G = set_num_nodes(G,num_nodes) | |
if largest_connected_component: | |
G = max(nx.connected_component_subgraphs(G), key=len) | |
nodes = list(G.nodes()) | |
edges = list(G.edges()) | |
# check for empty nodes and edges after getting subgraph of G | |
if not nodes: | |
print ('There are no nodes in the graph. Try increasing num_nodes.') | |
return | |
if not edges: | |
print ('There are no edges in the graph. Try increasing num_nodes.') | |
return | |
# set position of each node | |
if k is None: | |
pos = nx.spring_layout(G) | |
else: | |
pos = nx.spring_layout(G,k=k) | |
xpos,ypos=zip(*pos.values()) | |
nx.set_node_attributes(G, name = 'xpos', values = dict(zip(pos.keys(),[x*1000 for x in xpos]))) | |
nx.set_node_attributes(G, name = 'ypos', values = dict(zip(pos.keys(),[y*1000 for y in ypos]))) | |
# set the border width of nodes | |
if 'node_border_width' not in kwargs.keys(): | |
kwargs['node_border_width'] = 2 | |
border_width = {} | |
for n in nodes: | |
if n in seed_nodes_1 or n in seed_nodes_2: | |
border_width[n] = kwargs['node_border_width'] | |
elif highlight_nodes is not None and n in highlight_nodes: | |
border_width[n] = kwargs['node_border_width'] | |
else: | |
border_width[n] = 0 | |
nx.set_node_attributes(G, name = 'nodeOutline', values = border_width) | |
# set the shape of each node | |
nodes_shape=[] | |
for node in G.nodes(): | |
if node in seed_nodes_1: | |
nodes_shape.append('triangle') | |
elif node in seed_nodes_2: | |
nodes_shape.append('square') | |
else: | |
nodes_shape.append('dot') | |
node_to_shape=dict(zip(G.nodes(),nodes_shape)) | |
nx.set_node_attributes(G, name = 'nodeShape', values = node_to_shape) | |
# add a field for node labels | |
if highlight_nodes: | |
node_labels = {} | |
for node in nodes: | |
if node in seed_nodes_1 or n in seed_nodes_2: | |
node_labels[node] = str(node) | |
elif node in highlight_nodes: | |
node_labels[node] = str(node) | |
else: | |
node_labels[node] = '' | |
else: | |
node_labels = {n:str(n) for n in nodes} | |
nx.set_node_attributes(G, name = 'nodeLabel', values = node_labels) | |
# set the title of each node | |
node_titles = [str(node[0]) + '<br/>heat = ' + str(round(node[1]['node_heat'],10)) | |
for node in G.nodes(data=True)] | |
node_titles = dict(zip(nodes,node_titles)) | |
nx.set_node_attributes(G, name = 'nodeTitle', values = node_titles) | |
# set the color of each node | |
node_to_color = visJS_module.return_node_to_color(G, | |
field_to_map='node_heat', | |
cmap=node_cmap, | |
color_vals_transform='log') | |
# set heat value of edge based off hottest connecting node's value | |
node_attr = nx.get_node_attributes(G,'node_heat') | |
edge_weights = {} | |
for e in edges: | |
if node_attr[e[0]] > node_attr[e[1]]: | |
edge_weights[e] = node_attr[e[0]] | |
else: | |
edge_weights[e] = node_attr[e[1]] | |
nx.set_edge_attributes(G, name = 'edge_weight', values = edge_weights) | |
# set the color of each edge | |
edge_to_color = visJS_module.return_edge_to_color(G, | |
field_to_map = 'edge_weight', | |
cmap=edge_cmap, | |
color_vals_transform = 'log') | |
# create the nodes_dict with all relevant fields | |
nodes_dict = [{'id':str(n), | |
'border_width':border_width[n], | |
'degree':G.degree(n), | |
'color':node_to_color[n], | |
'node_label':node_labels[n], | |
'node_size':node_size, | |
'node_shape':node_to_shape[n], | |
'title':node_titles[n], | |
'x':np.float64(pos[n][0]).item()*1000, | |
'y':np.float64(pos[n][1]).item()*1000} for n in nodes] | |
# map nodes to indices for source/target in edges | |
node_map = dict(zip(nodes, range(len(nodes)))) | |
# create the edges_dict with all relevant fields | |
edges_dict = [{'source':node_map[edges[i][0]], | |
'target':node_map[edges[i][1]], | |
'color':edge_to_color[edges[i]]} for i in range(len(edges))] | |
# set node_size_multiplier to increase node size as graph gets smaller | |
if 'node_size_multiplier' not in kwargs.keys(): | |
if len(nodes) > 500: | |
kwargs['node_size_multiplier'] = 1 | |
elif len(nodes) > 200: | |
kwargs['node_size_multiplier'] = 3 | |
else: | |
kwargs['node_size_multiplier'] = 5 | |
kwargs['physics_enabled'] = physics_enabled | |
# if node hovering color not set, set default to black | |
if 'node_color_hover_background' not in kwargs.keys(): | |
kwargs['node_color_hover_background'] = 'black' | |
# node size determined by size in nodes_dict, not by id | |
if 'node_size_field' not in kwargs.keys(): | |
kwargs['node_size_field'] = 'node_size' | |
# node label determined by value in nodes_dict | |
if 'node_label_field' not in kwargs.keys(): | |
kwargs['node_label_field'] = 'node_label' | |
# export the network to JSON for Cytoscape | |
if export_network: | |
node_colors = map_node_to_color(G,'node_heat',True) | |
nx.set_node_attributes(G, name = 'nodeColor', values = node_colors) | |
edge_colors = map_edge_to_color(G,'edge_weight',True) | |
nx.set_edge_attributes(G, name = 'edgeColor', values = edge_colors) | |
visJS_module.export_to_cytoscape(G = G,export_file = export_file) | |
return visJS_module.visjs_network(nodes_dict,edges_dict,**kwargs) | |
def normalized_adj_matrix(G,conserve_heat=True,weighted=False): | |
''' | |
This function returns normalized adjacency matrix. | |
Inputs: | |
- G: NetworkX graph from which to calculate normalized adjacency matrix | |
- conserve_heat: | |
- True: Heat will be conserved (sum of heat vector = 1). Graph asymmetric | |
- False: Heat will not be conserved. Graph symmetric. | |
Returns: | |
- numpy array of the normalized adjacency matrix. | |
''' | |
wvec=[] | |
for e in G.edges(data=True): | |
v1 = e[0] | |
v2 = e[1] | |
deg1 = G.degree(v1) | |
deg2 = G.degree(v2) | |
if weighted: | |
weight = e[2]['weight'] | |
else: | |
weight=1 | |
if conserve_heat: | |
wvec.append((v1,v2,weight/float(deg2))) #np.sqrt(deg1*deg2))) | |
wvec.append((v2,v1,weight/float(deg1))) | |
else: | |
wvec.append((v1,v2,weight/np.sqrt(deg1*deg2))) | |
if conserve_heat: | |
# if conserving heat, make G_weighted a di-graph (not symmetric) | |
G_weighted= nx.DiGraph() | |
else: | |
# if not conserving heat, make G_weighted a simple graph (symmetric) | |
G_weighted = nx.Graph() | |
G_weighted.add_weighted_edges_from(wvec) | |
Wprime = nx.to_numpy_matrix(G_weighted,nodelist=list(G.nodes())) | |
Wprime = np.array(Wprime) | |
return Wprime | |
def network_propagation(G,Wprime,seed_nodes,alpha=.5, num_its=20): | |
''' | |
This function implements network propagation, as detailed in: | |
Vanunu, Oron, et al. 'Associating genes and protein complexes with disease | |
via network propagation.' | |
Inputs: | |
- G: NetworkX graph on which to run simulation | |
- Wprime: Normalized adjacency matrix (from normalized_adj_matrix) | |
- seed_nodes: Genes on which to initialize the simulation. | |
- alpha: Heat dissipation coefficient. Default = 0.5 | |
- num_its: Number of iterations (Default = 20. Convergence usually happens within 10) | |
Returns: | |
- Fnew: heat vector after propagation | |
''' | |
nodes = list(G.nodes()) | |
numnodes = len(nodes) | |
edges= list(G.edges()) | |
numedges = len(edges) | |
Fold = np.zeros(numnodes) | |
Fold = pd.Series(Fold,index=list(G.nodes())) | |
Y = np.zeros(numnodes) | |
Y = pd.Series(Y,index=list(G.nodes())) | |
for g in seed_nodes: | |
# normalize total amount of heat added, allow for replacement | |
Y[g] = Y[g]+1/float(len(seed_nodes)) | |
Fold = Y.copy(deep=True) | |
for t in range(num_its): | |
Fnew = alpha*np.dot(Wprime,Fold) + np.multiply(1-alpha,Y) | |
Fold=Fnew | |
return Fnew | |
def set_num_nodes(G, num_nodes): | |
''' | |
Sets whether the graph should be physics-enabled or not. It is set for | |
graphs of fewer than 100 nodes. | |
Inputs: | |
- G: a networkX graph | |
- num_nodes: the number of the hottest nodes to graph | |
Returns: | |
- networkX graph that is the subgraph of G with the num_nodes hottest | |
nodes | |
''' | |
if num_nodes != None and num_nodes < len(G.nodes()): | |
node_heat = [(node[0], node[1]['node_heat']) for node in G.nodes(data=True)] | |
nodes_sorted = sorted(node_heat, key=lambda x: x[1], reverse=True) | |
top_hottest_nodes = [nodes_sorted[i][0] for i in range(num_nodes)] | |
return G.subgraph(top_hottest_nodes) | |
return G | |
def map_node_to_color(G,field_to_map,color_vals_transform): | |
''' | |
Maps node to color value between 0 and 1 based on the given field. | |
Inputs: | |
- G: networkX graph | |
- field_to_map: node attribute to map color to | |
- color_vals_transform: to calculate color vals with log (boolean) | |
Returns: | |
- Dictionary that maps node to color value. | |
''' | |
node_to_field = [(n[0], max(n[1][field_to_map], 10**-18)) | |
for n in G.nodes(data=True)] | |
nodes,data = zip(*node_to_field) | |
if color_vals_transform: | |
nonzero_list = [d for d in data if d>(10**-18)] | |
if not nonzero_list: | |
data = [1 for d in data] | |
else: | |
min_val = min(nonzero_list) | |
data = [np.log(max(d,min_val)) for d in data] #set 0 vals to min val | |
data = [(d-np.min(data)) for d in data] #shift so we don't have neg vals | |
min_val = np.min(data) | |
max_val = np.max(data) - min_val | |
color_list = [float(d-min_val)/max_val for d in data] | |
return dict(zip(G.nodes(),color_list)) | |
def map_edge_to_color(G,field_to_map,color_vals_transform): | |
''' | |
Maps edge to color value between 0 and 1 based on the given field. | |
Inputs: | |
- G: networkX graph | |
- field_to_map: edge attribute to map color to | |
- color_vals_transform: to calculate color vals with log (boolean) | |
Returns: | |
- Dictionary that maps edge to color value. | |
''' | |
edges_data = [(e[0],e[1],e[2][field_to_map]) | |
for e in G.edges(data=True)] | |
edges1,edges2,data = zip(*edges_data) | |
if color_vals_transform: | |
nonzero_list = [d for d in data if d>(10**-18)] | |
if not nonzero_list: | |
data = [1 for d in data] | |
else: | |
min_dn0 = min([d for d in data if d>(10**-18)]) | |
data = [np.log(max(d,min_dn0)) for d in data] #set 0 vals to min val | |
data = [(d-np.min(data)) for d in data] #shift so we don't have neg vals | |
edges_data = zip(zip(edges1,edges2),data) | |
edge_to_field = dict(edges_data) | |
min_val = np.min(list(edge_to_field.values())) | |
max_val = np.max(list(edge_to_field.values())) - min_val | |
color_list = [float(edge_to_field[e]-min_val)/max_val for e in G.edges()] | |
return dict(zip(G.edges(),color_list)) |