Error in getting specific node shape, edge color and edge weight

38 Views Asked by At

I want to plot a directed graph for a group of genes. Let's say some genes are oncogenes, and some are driver genes. Further, the gene-gene interactions are weighted and represented using specific shapes and colours. I am using the following code to draw the directed graph:


    import networkx as nx
    import matplotlib.pyplot as plt
    import numpy as np
    
    # Your weighted adjacency matrix (replace this with your actual matrix)
    adjacency_matrix = np.array([
        [0, 0.2, 0, 0, 0.4],
        [0.0, 0, 0, 0, 0.1],
        [0.1, 0, 0, 0.1, 0],
        [0, 0, 0.3, 0, 0],
        [0.0, 0.0, 0, 0, 0]
    ])
    
    # Your Katz centrality scores (replace this with your actual scores)
    katz_centrality_scores = [0.95, 0.03, 0.65, 0.12, 0.06]
    # Relative scaling to range [1,10]
    katz_centrality_scores = [9*(i-min(katz_centrality_scores))/(max(katz_centrality_scores) - min(katz_centrality_scores)) + 1 for i in katz_centrality_scores]
    
    # Gene labels (replace with your gene labels)
    gene_labels = ["Gene1", "Gene2", "Gene3", "Gene4", "Gene5"]
    
    # Gene types (1 for oncogene, 2 for driver gene)
    gene_types = [1, 2, 1, 2, 2]
    
    # Create a graph
    G = nx.DiGraph()
    
    # Add nodes with attributes
    for i in range(len(gene_labels)):
        node_color = 'red' if gene_types[i] == 1 else 'green'
        node_shape = 'v' if gene_types[i] == 1 else 's'
        node_size = katz_centrality_scores[i]*80  # Adjust the scaling factor as needed
        G.add_node(gene_labels[i], color=node_color, shape=node_shape, size=node_size)
    
    node_colors = [v['color'] for v in dict(G.nodes(data=True)).values()]
    # Add edges from the adjacency matrix
    for i in range(len(gene_labels)):
        for j in range(len(gene_labels)):
            if adjacency_matrix[i][j] > 0:
                G.add_edge(gene_labels[i], gene_labels[j], weight=katz_centrality_scores[i], color=node_colors[i])
    
    # Extract node attributes
    node_colors = [G.nodes[n]['color'] for n in G.nodes()]
    node_shapes = [G.nodes[n]['shape'] for n in G.nodes()]
    node_sizes = [G.nodes[n]['size'] for n in G.nodes()]
    edge_colors = [G[u][v]['color'] for u, v in G.edges()]
    
    # Extract edge weights
    edge_weights = [G[u][v]['weight'] for u, v in G.edges()]
    
    # Draw the graph
    pos = nx.spring_layout(G, seed=42)  # You can use other layout algorithms
    curved_edges = [edge for edge in G.edges() if reversed(edge) in G.edges()]
    straight_edges = [edge for edge in G.edges() if not reversed(edge) in G.edges()]
    
    nx.draw(G, 
            pos, 
            node_color=node_colors, 
            node_size=node_sizes, 
            edge_color=edge_colors, 
            # node_shape=node_shapes,
            width=edge_weights, 
            with_labels=True, 
            edgelist=straight_edges, 
            arrowsize=25, 
            arrowstyle='->')
    
    nx.draw(G, 
            pos, 
            node_color=node_colors, 
            node_size=node_sizes, 
            edge_color=edge_colors, 
            # node_shape=node_shapes,
            width=edge_weights, 
            with_labels=True, 
            edgelist=curved_edges, 
            connectionstyle='arc3, rad = 0.25',
            arrowsize=25,
            arrowstyle='->')
    
    # Create a legend
    red_patch = plt.Line2D([0], [0], marker='v', color='red', label='Oncogene', markersize=10, linestyle='None')
    green_patch = plt.Line2D([0], [0], marker='s', color='green', label='Driver Gene', markersize=10, linestyle='None')
    plt.legend(handles=[red_patch, green_patch], loc='upper right')
    
    # Show the plot
    plt.title('Gene Network')
    plt.axis('off')  # Turn off axis labels and ticks
    plt.show()

After running the above code, the graph edge attribute is as follows:

 list(G.edges(data=True))

 [('Gene1', 'Gene2', {'weight': 10.0, 'color': 'red'}),
 ('Gene1', 'Gene5', {'weight': 10.0, 'color': 'red'}),
 ('Gene2', 'Gene5', {'weight': 1.0, 'color': 'green'}),
 ('Gene3', 'Gene1', {'weight': 7.065217391304349, 'color': 'red'}),
 ('Gene3', 'Gene4', {'weight': 7.065217391304349, 'color': 'red'}),
 ('Gene4', 'Gene3', {'weight': 1.8804347826086958, 'color': 'green'})]

`

The above code is generating the following graph (which is not correct):

Output directed graph

Please note that the image is not according to the node and edge criteria mentioned in the code. For example,

  1. The edge colour and weight for an edge for node pair (Gene3, Gene4) and (Gene4, Gene3) are (red,7.06) and (green,1.88). But in the generated graph, the edge between (Gene4, Gene3) the colour is shown as red (not green), and the edge thickness is the same as (Gene3, Gene4) (which is wrong).

  2. When I uncomment the node_shape argument in nx.draw, I get the following error:ValueError: Unrecognized marker style ['v', 's', 'v', 's', 's']. I am not able to figure out how to give the node shape for each gene category (e.g., triangle for oncogene and square for driver gene)

Can anyone suggest to me what I am missing in the above code?

Thanks.

1

There are 1 best solutions below

0
ravenspoint On
curved_edges = [edge for edge in G.edges() if reversed(edge) in G.edges()]
straight_edges = [edge for edge in G.edges() if not reversed(edge) in G.edges()]

You have two different lists here and call draw twice, once for each. However on each call you pass the same list of colors

edge_color=edge_colors, 

You need two lists of colors, one for straight edges and one for curved edges so that the draw method will get the correct color for each edge.