Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
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))
Beispiel #4
0
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)
Beispiel #5
0
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)