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 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 visualize_visjs(G, communities=None, colors=None, default_color="192,192,192", node_size_field="node_size", layout="spring", scale=500, pos=None, groups=None, weight=None, labels=dict(), title=""): # Get list of nodes and edges nodes = list(G.nodes()) edges = list(G.edges()) # Change node shapes for bipartite graph if groups is None: node_shapes = dict() node_sizes = dict() node_colors = dict() else: node_shapes = dict((n, "square") for n in groups) node_sizes = dict((n, 15) for n in groups) node_colors = dict((n, "192,128,0") for n in groups) # Per-node properties nodes_dict = dict((n, { "id": labels.get(n, n), "node_size": node_sizes.get(n, 5), "node_shape": node_shapes.get(n, "dot") }) for n in nodes) # Generate a layout for the nodes edge_smooth_enabled = False edge_width = 4 edge_arrow_scale = 2 if communities is not None and pos is None: # Generate initial positions based on community phi = 3.14 / len(nodes) community_node = [] # Create list of nodes and their communities for i, com in enumerate( sorted(communities, key=lambda x: len(x), reverse=True)): for node in com: community_node.append((i, node)) # Sort by community and community_node = sorted(community_node) # Generate initial position by placing communities around a circle pos = dict((d[1], (math.cos(i * phi), math.sin(i * phi))) for i, d in enumerate(community_node)) else: pos = None if layout == "circle": pos = nx.circular_layout(G, scale=scale) elif layout == "spring": pos = nx.spring_layout(G, k=3 / math.sqrt(len(nodes)), scale=scale, pos=pos) else: edge_smooth_enabled = True # Assign position for n in nodes: nodes_dict[n]["x"] = pos[n][0] nodes_dict[n]["y"] = pos[n][1] # Calculate bounds for scaling x_min = min(pos.values(), key=lambda x: x[0])[0] x_max = max(pos.values(), key=lambda x: x[0])[0] y_min = min(pos.values(), key=lambda x: x[1])[1] y_max = max(pos.values(), key=lambda x: x[1])[1] x_range = x_max - x_min y_range = y_max - y_min max_range = max(x_range, y_range) # If we have communities, assign color based on community if colors is None: colors = ["{},{},{}".format(*c) for c in get_colors()] if communities is not None: for i, com in enumerate( sorted(communities, key=lambda x: len(x), reverse=True)): for node in com: try: nodes_dict[node]["color"] = "rgba({},1)".format(colors[i]) nodes_dict[node]["color_index"] = i except IndexError: nodes_dict[node]["color"] = "rgba({},1)".format( default_color) # Update color for bipartite nodes for node, node_attr in nodes_dict.items(): if node in node_colors: node_attr["color"] = "rgba({},1)".format(node_colors[node]) # Map node labels to contiguous ids node_map = dict(zip(nodes, range(len(nodes)))) # Determine edge colors edge_colors_idx = {} for source, target in edges: source_color = nodes_dict[source].get("color_index", None) target_color = nodes_dict[target].get("color_index", None) if source_color == target_color and source_color is not None: edge_colors_idx[(source, target)] = source_color edge_colors = dict( (e, colors[c]) for e, c in edge_colors_idx.items() if c < len(colors)) # Per-edge properties, use contiguous ids to identify nodes edge_scale = math.ceil(max_range / 200) edges_dict = [] for source, target, data in G.edges(data=True): edge = { "source": node_map[source], "target": node_map[target], "title": 'test', "color": "rgba({},0.3)".format( edge_colors.get((source, target), default_color)), "edge_width_field": "value", "value": data.get("value", 1) * edge_scale } edges_dict.append(edge) # Convert nodes dict to node list nodes_list = [nodes_dict[n] for n in nodes] # Check for directed graph if G.__class__ == nx.classes.digraph.DiGraph: directed = True else: directed = False # Call visjs return vjs.visjs_network(nodes_list, edges_dict, node_size_field="node_size", node_size_multiplier=10.0, edge_width_field="value", edge_width=edge_width, edge_arrow_to=directed, edge_arrow_to_scale_factor=edge_arrow_scale, edge_smooth_enabled=edge_smooth_enabled, edge_smooth_type="curvedCW", graph_id=hash(title))
nodes_dict[0] # In[38]: # save the dicts for later viewing with open('{0:s}/nodes.json'.format(output_path), 'w') as f: json.dump(nodes_dict, f, sort_keys=True, indent=2) with open('{0:s}/edges.json'.format(output_path), 'w') as f: json.dump(edges_dict, f, sort_keys=True, indent=2) # In[ ]: visJS_module.visjs_network(nodes_dict, edges_dict, node_size_field='node_size', node_size_transform='Math.log', node_size_multiplier=2, node_font_size=0, edge_width=9, edge_title_field="title", physics_enabled=False, graph_title="Interactive Steam Graph", graph_width=940, graph_height=600, border_color='black', tooltip_delay=0, graph_id=0, config_enabled=False)
def pathwayVisualization(KEGG_id, path_to_csv, redirect=True, compound=False): """ The pathwayVisualization function returns a graph visualization based on user input Args: KEGG_id (str): string specifying KEGG pathway ID to visualize path_to_csv (str): string specifying data to overlay on graph redirect (bool): True to split nodes into their components. Defaults to True compound (bool): True to display compounds (such as Ca2+). Defaults to False Returns: A graph visualization using the visjs_network function from visjs_2_jupyter """ s = KEGG() res = s.get(KEGG_id, "kgml") if res == 404 or res == 400: print KEGG_id + ' is not a valid KEGG ID' return result = s.parse_kgml_pathway(KEGG_id) ETroot = parsingXML(KEGG_id, s) G=nx.DiGraph() max_id, compound_array = addNodes(G, result) setCoord(G, ETroot) if redirect is False: getNodeSymbols(G, s, compound) else: parent_list, parent_dict = splitNodes(G, s, max_id) complex_array, component_array, node_dict, comp_dict = undefNodes(G, ETroot) if redirect is False: addEdges(G, result, component_array, node_dict) else: addAndRedirectEdges(G, result, complex_array, component_array, parent_list, parent_dict, node_dict, comp_dict) #add reactions to graph addReaction(G, ETroot) edge_to_name = dict() for edge in G.edges(): if G.edge[edge[0]][edge[1]]['name'] == 'phosphorylation': edge_to_name[edge] = G.edge[edge[0]][edge[1]]['value'] elif G.edge[edge[0]][edge[1]]['name'] == 'dephosphorylation': edge_to_name[edge] = G.edge[edge[0]][edge[1]]['value'] elif 'dephosphorylation' in G.edge[edge[0]][edge[1]]['name']: edge_to_name[edge] = G.edge[edge[0]][edge[1]]['name'].replace('dephosphorylation', '-p') elif 'phosphorylation' in G.edge[edge[0]][edge[1]]['name']: edge_to_name[edge] = G.edge[edge[0]][edge[1]]['name'].replace('phosphorylation', '+p') else: edge_to_name[edge] = G.edge[edge[0]][edge[1]]['name'] edge_to_name[edge] = edge_to_name[edge].replace('activation, ', '') edge_to_name[edge] = edge_to_name[edge].replace('inhibition, ', '') edge_to_name[edge] = edge_to_name[edge].replace('activation', '') edge_to_name[edge] = edge_to_name[edge].replace('inhibition', '') #edges are transparent edge_to_color = dict() for edge in G.edges(): if 'activation' in G.edge[edge[0]][edge[1]]['name']: edge_to_color[edge] = 'rgba(26, 148, 49, 0.3)' #green elif 'inhibition' in G.edge[edge[0]][edge[1]]['name']: edge_to_color[edge] = 'rgba(255, 0, 0, 0.3)' #red else: edge_to_color[edge] = 'rgba(0, 0, 255, 0.3)' #blue #for graph with split nodes if redirect is True: #remove undefined nodes from graph G.remove_nodes_from(complex_array) #remove nodes with more than one gene G.remove_nodes_from(parent_list) if compound is False: #remove compound nodes G.remove_nodes_from(compound_array) node_to_symbol = dict() for node in G.node: if G.node[node]['type'] == 'map': node_to_symbol[node] = G.node[node]['gene_names'] else: if 'symbol' in G.node[node]: node_to_symbol[node] = G.node[node]['symbol'] elif 'gene_names'in G.node[node]: node_to_symbol[node] = G.node[node]['gene_names'] else: node_to_symbol[node] = G.node[node]['name'] # getting name of nodes node_to_gene = dict() for node in G.node: node_to_gene[node] = G.node[node]['gene_names'] # getting x coord of nodes node_to_x = dict() for node in G.node: node_to_x[node] = G.node[node]['x'] # getting y coord of nodes node_to_y = dict() for node in G.node: node_to_y[node] = G.node[node]['y'] id_to_log2fold = log2FoldChange(G, path_to_csv) # Create color scale with negative as green and positive as red my_scale = spectra.scale([ "green", "#CCC", "red" ]).domain([ -4, 0, 4 ]) # color nodes based on log2fold data node_to_color = dict() for node in G.nodes(): if node in id_to_log2fold: node_to_color[node] = my_scale(id_to_log2fold[node][0]).hexcode else: node_to_color[node] = '#f1f1f1' # getting nodes in graph nodes = G.nodes() numnodes = len(nodes) node_map = dict(zip(nodes,range(numnodes))) # map to indices for source/target in edges # getting edges in graph edges = G.edges() numedges = len(edges) # dictionaries that hold per node and per edge attributes nodes_dict = [{"id":node_to_gene[n],"degree":G.degree(n),"color":node_to_color[n], "node_shape":"box", "node_size":10,'border_width':1, "id_num":node_to_symbol[n], "x":node_to_x[n], "y":node_to_y[n]} for n in nodes] edges_dict = [{"source":node_map[edges[i][0]], "target":node_map[edges[i][1]], "color":edge_to_color[edges[i]], "id":edge_to_name[edges[i]], "edge_label":'', "hidden":'false', "physics":'true'} for i in range(numedges)] # html file label for first graph (must manually increment later) time = 1700 # create graph here #return G return visJS_module.visjs_network(nodes_dict, edges_dict, time_stamp = time, node_label_field = "id_num", edge_width = 3, border_color = "black", edge_arrow_to = True, edge_font_size = 15, edge_font_align= "top", physics_enabled = False, graph_width = 1000, graph_height = 1000)